java.lang Exception hierarchy - why?

D

Dan Wilkin

I have been having trouble understanding the motivation regarding the
inheritance hierarchy established with the top level exception classes
in java.lang. More specifically, I am wondering why java.lang.
RuntimeException (an unchecked exception) has been placed as a subclass
to java.lang.Exception (a checked exception)? An example:

public void A() {
try {
doWork();
doMoreWork();
doDiffWork();
catch (Exception e) {
System.out.error("An error occurred!");
e.printStackTrace();
processAnticipatedError(e);
}
}

In this sample try/catch block I would like to catch all propagated
checked exceptions that have potentially been thrown, yet declared by
the methods doWork(), doMoreWork(), doDiffWork() -- i.e. these methods
have declared they will throw checked exceptions. However, I do not
want to catch any runtime exceptions (RuntimeException and it's
subclasses) - I want those to propegate to my main() and crash my
program (or get handled gracefully there) so that I can know that I have
introduced a bad programming decision into my code that is failing the
contract of a lower level method (e.g., passing null somewhere thus
instigating an IllegalArgumentException, attempting to create a very
large object and running out of memory, etc.). At this point the code
above would catch *all* runtime exceptions as well as the checked
exceptions I was anticipating!!

Can someone give me a clear explaination why the Java authors created
the hierarchy in this way? Is there a JSR issue opened on this
particular item? Perhaps catching the general Exception class in this
case is poor programming practice and I should be writing catch blocks
for all possible checked exceptions (in which case they'd all be the
same - handled by my generic error handler - which in and of itself
stands for debate).

Nevertheless and in short, I would prefer to see Exception a subclass of
RuntimeException and checked/unchecked markings would hold to their
original classes within the JVM and Java language
specification/implementation (since this is also verified at compile
time). In other words, RuntimeException would still be an unchecked
exception and all its subclasses - except for Exception which would be
marked as checked, all subclasses of Exception would likewise be marked
as checked. RuntimeException would inherit from Throwable.

Dan
 
C

Carl Howells

Dan said:
In this sample try/catch block I would like to catch all propagated
checked exceptions that have potentially been thrown, yet declared by
the methods doWork(), doMoreWork(), doDiffWork() -- i.e. these methods
have declared they will throw checked exceptions. However, I do not
want to catch any runtime exceptions (RuntimeException and it's
subclasses) - I want those to propegate to my main() and crash my
program (or get handled gracefully there) so that I can know that I have
introduced a bad programming decision into my code that is failing the
contract of a lower level method (e.g., passing null somewhere thus
instigating an IllegalArgumentException, attempting to create a very
large object and running out of memory, etc.). At this point the code
above would catch *all* runtime exceptions as well as the checked
exceptions I was anticipating!!

Well, that's easy enough to solve. I can't answer the rest of your
questions, but I can do this much for you. The code you want looks like
this:

try
{
// stuff that could throw many exceptions here
}
catch (RuntimeException e)
{
throw e;
}
catch (Exception e)
{
// process anticipated checked exceptions here
}

And, in fact, instead of catching Exception, you should probably have a
separate catch block for each subclass of Exception you expect to get,
just because it makes the code much cleaner.

The key for this working is that when a try block has multiple catch
blocks, any exception thrown within that block is matched against the
catch blocks from the top down, and only the first block that matches
the exception is used to handle the exception. When a RuntimeException
is caught, it's just thrown again immediately, passing the exception
back along the chain.
 
D

Dan Wilkin

Hmmm. No that's not the problem. Im clearly aware of that alternative.
The point is that your solution required that you catch the
RuntimeException explicitly, then rethrow it. Good programming practice
dictates that one does not generally catch RuntimeExceptions. That's
the point of unchecked exceptions - to surpass traditional handling and
make the developer aware of a runtime error in the code, prior shipping
the product. A runtime error can indicate failure to comply with the
contract of a method or a configuration problem in the case there is an
error allocating memory. There are many other's but these are two
frequently uses for RuntimeExceptions - unchecked exceptions. Premise:
unchecked could be loosely coined as unhandled or more accurately, not
formally handled. The language does not intend for you to catch these
exceptions -- so why is it a subclass of a checked exception?
 
C

Chris Uppal

Dan said:
Can someone give me a clear explaination why the Java authors created
the hierarchy in this way?

Not I. My own opinion is that they got it wrong.

But that it's also *way* too late to change it.

-- chris
 
M

Manavendra Gupta

Dan Wilkin said:
I have been having trouble understanding the motivation regarding the
inheritance hierarchy established with the top level exception classes
in java.lang. More specifically, I am wondering why java.lang.
RuntimeException (an unchecked exception) has been placed as a subclass
to java.lang.Exception (a checked exception)?

Before we delve into the dicussion, lets recall the Java Exception
hierarchy:
Throwable
+---Error (shouldn't catch)
+ Exception
++IOException
++FileNotFoundException
++... (etc)...
+ RunTimeException
++NullPointerException
++IndexOutOfBoundsException
++... (etc)...

Note that the language defines two types of "exceptions" - recoverable
errors, that should be handled allowing the program to terminate gracefully,
and unrecoverable errors.

The unchecked exceptions classes are the class RuntimeException and its
subclasses, and the class Error and its subclasses. All other exception
classes are checked exception classes

Errors are not checked and are exempted from compile time checking because
they can occur at many points in the program and recovery from them is
difficult or impossible. A program declaring such exceptions would be
cluttered, pointlessly(JLS, 11.2.1).
In this sample try/catch block I would like to catch all propagated
checked exceptions that have potentially been thrown, yet declared by
the methods doWork(), doMoreWork(), doDiffWork() -- i.e. these methods
have declared they will throw checked exceptions.
Since your methods have declared (checked) exceptions, you clearly have a
public contract that the callers of your methods should take into
consideration. With exceptions, the big debate has always been whether and
when to declare checked exceptions. This controversy is documented at:
http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html
However, I do not
want to catch any runtime exceptions (RuntimeException and it's
subclasses) - I want those to propegate to my main() and crash my
program (or get handled gracefully there) so that I can know that I have
introduced a bad programming decision into my code that is failing the
contract of a lower level method (e.g., passing null somewhere thus
instigating an IllegalArgumentException, attempting to create a very
large object and running out of memory, etc.).
Well, this again is a contradiction in terms. You want to catch "all"
exceptions, which means you want to catch all "recoverable" exceptions.
RunTimeExceptions are recoverable, and hence catching an instance of
Exception is the equivalent of stating you want to handle everything that
has possibly gone wrong and that you can recover from.

FYI, the exception when "running out of memory" is not a runtime exception,
but an Error, hence irrecoverable.
At this point the code
above would catch *all* runtime exceptions as well as the checked
exceptions I was anticipating!!
Which is exactly what is required! If you have checked exceptions then the
callers *know* what all could possibly go wrong and will have alternatives
tucked into the code. It is only if something other than the possibles
happens that you want an "umbrella" class to catch and act upon (fail
gracefully, in most cases).
Can someone give me a clear explaination why the Java authors created
the hierarchy in this way?
From the holy grail: The runtime exception classes (RuntimeException and its
subclasses) are exempted from compile-time checking because, in the judgment
of the designers of the Java programming language, having to declare such
exceptions would not aid significantly in establishing the correctness of
programs. Many of the operations and constructs of the Java programming
language can result in runtime exceptions. The information available to a
compiler, and the level of analysis the compiler performs, are usually not
sufficient to establish that such run-time exceptions cannot occur, even
though this may be obvious to the programmer. Requiring such exception
classes to be declared would simply be an irritation to programmers.
For example, certain code might implement a circular data structure that, by
construction, can never involve null references; the programmer can then be
certain that a NullPointerException cannot occur, but it would be difficult
for a compiler to prove it. The theorem-proving technology that is needed to
establish such global properties of data structures is beyond the scope of
this specification (JLS, 11.2.2)

In essence, almost all subclasses of Exception must be dealt with. There is
a subclass of Exception which doesn't require handling, and that is the
RunTimeException subclass. RunTimeException itself has subclasses, including
ArithmeticException and NumberFormatException. RunTimeExceptions are
normally within direct control of a Java program's code. Further, they
normally refer to coding errors, or situations which can be directly
rememedied with the Java code. A NullPointerException, a sublcass of
RunTimeException, indicates that a variable has null as its value but is
being sent a message. Fix: make sure that variable isn't null, which can be
done directly within Java. Compare this to a FileNotFoundException, which is
a sublcass of Exception but not of RunTimeException, and which indicates
that the specified file does not exist. Fix: tough to say. Perhaps look
somewhere else for the file, but likely just print out a suitable message
and try to continue on. Files are external to Java (null variables are not),
and are tougher to control.

Is there a JSR issue opened on this
particular item?
Not that I know of

Perhaps catching the general Exception class in this
case is poor programming practice and I should be writing catch blocks
for all possible checked exceptions (in which case they'd all be the
same - handled by my generic error handler - which in and of itself
stands for debate).
Exactly. If you look at the source of most widely used Java-based projects
(jakarta is a good example), in most super-classes you'd find a code-akin
to:

try {
// do your stuff here
} catch (typeA) {
} catch (typeB) {
}
// ... all other checked types
catch (Exception) { // something we dont know about
}

Nevertheless and in short, I would prefer to see Exception a subclass of
RuntimeException and checked/unchecked markings would hold to their
original classes within the JVM and Java language
specification/implementation (since this is also verified at compile
time). In other words, RuntimeException would still be an unchecked
exception and all its subclasses - except for Exception which would be
marked as checked, all subclasses of Exception would likewise be marked
as checked. RuntimeException would inherit from Throwable.
So all exceptions then become runtime exceptions? So a wise programmer can
then do away with all compile-time checking and simply catch all
RunTimeExceptions, eh? How do you then make available the information about
most obvious errors for the compiler to check for?

Manav
 
T

Timo Kinnunen

Dan Wilkin said:
Nevertheless and in short, I would prefer to see Exception a
subclass of RuntimeException

That wouldn't work, because uncheckedness is inherited. Consider a
hierarchy of a checked MyFooException which inherits from a checked
MyException. You can write throw new MyFooException and throws
MyException and all is well. Now change it to checked Exception which
inherits from an unchecked RuntimeException. You now no longer need to
write either throws Exception or throws RuntimeException, because
instead of writing throws Exception you could write throws
RuntimeException, which you don't need to write, because
RuntimeException is unchecked.
 
T

Timo Kinnunen

Chris Uppal said:
Not I. My own opinion is that they got it wrong.

The only workable alternative that I see would be to break the link
between Exception and RuntimeException. That would make it impossible
to write a catch-clause to catch all exceptions, which might not be
such a bad idea.
But that it's also *way* too late to change it.

Yup.
 
C

Chris Uppal

Timo said:
The only workable alternative that I see would be to break the link
between Exception and RuntimeException. That would make it impossible
to write a catch-clause to catch all exceptions, which might not be
such a bad idea.

One approach (if we could go back in time) would be to drop the idea of having
the distinction between checked and unchecked modelled by two branches of the
Throwable hierarchy. Instead make all Throwables unchecked by default, but use
a "marker" interface (CheckableException, say) to indicate which Exception
classes should be checked by the compiler. That would allow much more
flexibility in the choice of which exceptions were checked (e.g. one could have
a checkable subclass of NullPointerException), and would also allow one to
catch all checkable exceptions with code like:

try
{
...
}
catch (CheckableException e)
{
...
}

or to distinguish between checkable and uncheckable with:

try
{
...
}
catch (CheckableException e)
{
// worth seeing if we can recover
logItAndRestart(e);
}
catch (Throwable e)
{
// hmm, probably fatal
logItAndDie(e);
}

Oh well...

-- chris
 
D

Dan Wilkin

Manav,

Thank you for your comments. I particularly appreciate the references
to the JLS in clearing this mud from the pool. Comments inline...

Manavendra said:
Before we delve into the dicussion, lets recall the Java Exception
hierarchy:
Throwable
+---Error (shouldn't catch)
+ Exception
++IOException
++FileNotFoundException
++... (etc)...
+ RunTimeException
++NullPointerException
++IndexOutOfBoundsException
++... (etc)...

Note that the language defines two types of "exceptions" - recoverable
errors, that should be handled allowing the program to terminate gracefully,
and unrecoverable errors.

The unchecked exceptions classes are the class RuntimeException and its
subclasses, and the class Error and its subclasses. All other exception
classes are checked exception classes

Errors are not checked and are exempted from compile time checking because
they can occur at many points in the program and recovery from them is
difficult or impossible. A program declaring such exceptions would be
cluttered, pointlessly(JLS, 11.2.1).

Agreed. I mistakenly recalled the placement of a memory allocation
error. As you said it is a subclass of Error. Also, I would strongly
agree that catching Errors and its subclasses would be a mistake in
programming - cluttered and pointless sums that up. Errors such as
those should have impedence placed to propagate up the stack. There
isn't much a programmer can do to resolve these and as such is generally
left up to the user to deal with (whether the user sees a stack trace or
a pretty error message is a seperate issue). So we can toss Errors and
its subclasses to the side. The issue is regarding catch blocks in
reference to unchecked and checked exceptions.
Since your methods have declared (checked) exceptions, you clearly have a
public contract that the callers of your methods should take into
consideration. With exceptions, the big debate has always been whether and
when to declare checked exceptions. This controversy is documented at:
http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html

Sure, when and where are issues truely debateable, yet not the focus of
my discussion here. But thanks for the reference to the fact.
Well, this again is a contradiction in terms. You want to catch "all"
exceptions, which means you want to catch all "recoverable" exceptions.
RunTimeExceptions are recoverable, and hence catching an instance of
Exception is the equivalent of stating you want to handle everything that
has possibly gone wrong and that you can recover from.

I fail to see the contradiction. Here was my goal (quoted):

"In this sample try/catch block I would like to catch all propagated
checked exceptions"

My desire is to catch all *checked* exceptions. Or from a different
perspective, I don't want to catch any exceptions or errors except
checked exceptions - which would at the top of the class hierarchy is
java.lang.Exception. I see how you may think that this means I want to
catch *all* exceptions. Try to bear with me here. java.lang.Exception
is the super class of all checked exceptions. Unfortunately, it's also
the superclass of the supermost unchecked exception - RuntimeException.
If I wanted to specify only one catch block to catch all *checked*
exceptions, I can't do it because by catching Exception I'll be catching
unchecked exceptions as well RuntimeException being the superclass of
all unchecked exceptions. A catch block such as this would as you say
catch all exceptions - which is not my intent.

Since an unchecked exception is not intended to always be caught - the
language should assist in enforcing this motive.

Unchecked exceptions should not be caught when the attempt is only to
catch checked exceptions. The current Java language inheritance
hierarchy prevents this by setting RuntimeException as a subclass to
Exception. This is the point of my argument. These two classes should
be swapped on the inheritance tree. Checked exceptions can continue to
inherit from Exception, and unchecked exceptions can continue to inherit
from RuntimeException.

So I would propose the following inheritance hierarchy:

Throwable
+---- Error (certifiably unrecoverable)
+- OutOfMemoryError
+- RuntimeException (unchecked, unrecoverable)
+- NullPointerException
+- IllegalArgumentException
+- Exception (checked, anticipate and recover)
+- IOException
+- FileNotFoundException
FYI, the exception when "running out of memory" is not a runtime exception,
but an Error, hence irrecoverable.



Which is exactly what is required! If you have checked exceptions then the
callers *know* what all could possibly go wrong and will have alternatives
tucked into the code. It is only if something other than the possibles
happens that you want an "umbrella" class to catch and act upon (fail
gracefully, in most cases).



From the holy grail: The runtime exception classes (RuntimeException and its
subclasses) are exempted from compile-time checking because, in the judgment
of the designers of the Java programming language, having to declare such
exceptions would not aid significantly in establishing the correctness of
programs. Many of the operations and constructs of the Java programming
language can result in runtime exceptions. The information available to a
compiler, and the level of analysis the compiler performs, are usually not
sufficient to establish that such run-time exceptions cannot occur, even
though this may be obvious to the programmer. Requiring such exception
classes to be declared would simply be an irritation to programmers.
For example, certain code might implement a circular data structure that, by
construction, can never involve null references; the programmer can then be
certain that a NullPointerException cannot occur, but it would be difficult
for a compiler to prove it. The theorem-proving technology that is needed to
establish such global properties of data structures is beyond the scope of
this specification (JLS, 11.2.2)

In essence, almost all subclasses of Exception must be dealt with. There is
a subclass of Exception which doesn't require handling, and that is the
RunTimeException subclass. RunTimeException itself has subclasses, including
ArithmeticException and NumberFormatException. RunTimeExceptions are
normally within direct control of a Java program's code. Further, they
normally refer to coding errors, or situations which can be directly
rememedied with the Java code. A NullPointerException, a sublcass of
RunTimeException, indicates that a variable has null as its value but is
being sent a message. Fix: make sure that variable isn't null, which can be
done directly within Java. Compare this to a FileNotFoundException, which is
a sublcass of Exception but not of RunTimeException, and which indicates
that the specified file does not exist. Fix: tough to say. Perhaps look
somewhere else for the file, but likely just print out a suitable message
and try to continue on. Files are external to Java (null variables are not),
and are tougher to control.




Not that I know of

Perhaps catching the general Exception class in this


Exactly. If you look at the source of most widely used Java-based projects
(jakarta is a good example), in most super-classes you'd find a code-akin
to:

try {
// do your stuff here
} catch (typeA) {
} catch (typeB) {
}
// ... all other checked types
catch (Exception) { // something we dont know about
}

Yes, traditionally, this is the desired clean approach. However, the
sample I chose was written to make a particular point.
So all exceptions then become runtime exceptions? So a wise programmer can
then do away with all compile-time checking and simply catch all
RunTimeExceptions, eh? How do you then make available the information about
most obvious errors for the compiler to check for?

No, not at all. Refer to my suggested revised inheritance hierarchy
(what I was suggesting previously but without the nifty tree diagram).
#1) A programmer should always be looking to catch and deal with checked
exceptions. #2) A programmer should never, by act of trying to complete
#1, be forced to handle unchecked exceptions. #3) A programmer should
be given the same flexibility in a catch block as is found in not being
required to declare unchecked exceptions in the signature of a method.
No requirement to declare unchecked exceptions - there should not be a
requirement to handle unchecked exceptions. The present inheritance
hierarchy does not support this.
 
M

Manavendra Gupta

Dan Wilkin said:
Thank you for your comments.
No problem.

So we can toss Errors and
its subclasses to the side. The issue is regarding catch blocks in
reference to unchecked and checked exceptions.
No worries. Lets re-open the issue then.


I fail to see the contradiction. Here was my goal (quoted):

"In this sample try/catch block I would like to catch all propagated
checked exceptions"

My desire is to catch all *checked* exceptions.
Is that statement really wrt to Java? If you have *checked* exceptions, then
IMO, you would want to deal with each exception individually. As the risk of
sounding rude, I would go back and examine my exception hierarchy if there
are any exceptions thrown that are redundant or do not provide a scenario
special enough to qualify for individual handling. The simple guideline,
which I'm sure you'd be aware of, is if you are throwing an exception for an
abnormal condition that you feel client programmers should consciously
decide how to handle, throw a checked exception.
Or from a different
perspective, I don't want to catch any exceptions or errors except
checked exceptions - which would at the top of the class hierarchy is
java.lang.Exception. I see how you may think that this means I want to
catch *all* exceptions. Try to bear with me here. java.lang.Exception
is the super class of all checked exceptions. Unfortunately, it's also
the superclass of the supermost unchecked exception - RuntimeException.
If I wanted to specify only one catch block to catch all *checked*
exceptions, I can't do it because by catching Exception I'll be catching
unchecked exceptions as well RuntimeException being the superclass of
all unchecked exceptions. A catch block such as this would as you say
catch all exceptions - which is not my intent.
And just why would you want to catch only *checked* exceptions? Is there any
specific behaviour that you have in mind that you would like to accomplish
by handling only *checked* exceptions? In all the years, I haven't come
across a single situation where I wanted to do something special if its a
runtime exception. Also it makes me wonder if you have a specific
user-defined runtime exception that you are worried about, then should it be
a runtime exception at all ?

I would again ask: if, as you suggest, runtime exceptions are superclasses
of checked exceptions, then are checked exceptions really *checked* ?
because, of course, their parent is unchecked, then a programmer does not
need to worry about them any longer, does he? From what I understand, there
isnt a "flag" or variable anywhere that says this exception is checked or
that this is unchecked. Unchecked exceptions are full-fledged classes in
themselves as well, and are pretty much the same as checked exceptions, with
the exception that 1) by declaring a runtime exception you specify that the
given scenario would depend upon a data/run time value and that such a
scenario would not normally occur and that programmers do not have to
explicity worry about such a situation and 2) because it is such an unlikely
situation, you are saying that the compiler does not have enough information
to check the semantics at compile time.
Since an unchecked exception is not intended to always be caught - the
language should assist in enforcing this motive.
And does it not? Every time i have a run time exception, I am able to
report,log and process it. If you handle the runtime exceptions before
everything else, don't you think the language provides what you need? So,
instead of your suggestion that all exceptions are runtime exceptions, the
JLS says the opposite - that runtime exceptions are a _type_ of exception !

So all exceptions then become runtime exceptions? So a wise programmer can

No, not at all. Refer to my suggested revised inheritance hierarchy
(what I was suggesting previously but without the nifty tree diagram).
#1) A programmer should always be looking to catch and deal with checked
exceptions.
Which is precisely what the JLS says. In fact, it goes a step further and
states you should deal and process each exception individually. And then it
goes a step further and provides you a mechanism to handle all possibly
exceptions in a generic manner thereby reducing your boilerplate code.
#2) A programmer should never, by act of trying to complete
#1, be forced to handle unchecked exceptions.
Just where and when is a programmer *forced* to handle unchecked exceptions?
Is there anywhere the spec says this? If a programmer catches only those
exceptions that are thrown by the method, is he not able to do so?
Furthermore, is a programmer not able to catch all exceptions in one go ?
#3) A programmer should
be given the same flexibility in a catch block as is found in not being
required to declare unchecked exceptions in the signature of a method.
And a programmer still has this flexibility. I have yet to come across a
single large-scale application (commercial or free) that has had any
problems in handling exceptions. Furthermore, most application would *want*
to define their own checked exceptions, which would not only define custom
errors, but also wrap the checked exceptions thrown by underlying libraries,
and provide a more readable message to the user. With the exception linkage
introduced in 1.4 onwards, the stack trace is not lost anymore. And the top
level classes in your libraries would need to catch only one checked
exception (well, in most cases).
No requirement to declare unchecked exceptions - there should not be a
requirement to handle unchecked exceptions.
Again, are all exceptions runtime or is runtime a type of exception? I'm
being convinced that you seem to think different :)

Manav
 
X

xarax

Dan Wilkin said:
Manav,

Thank you for your comments. I particularly appreciate the references
to the JLS in clearing this mud from the pool. Comments inline...
/snip/

A possible approach is to add new exception,
java.lang.CheckedException, under Exception:

hierarchy:
Throwable
+---Error (extends Throwable)
+ Exception (extends Throwable)
++CheckedException (extends Exception)
+++IOException (extends CheckedException)
+++FileNotFoundException (extends CheckedException)
+++... (etc)...
++RunTimeException (extends Exception)
+++NullPointerException (extends RunTimeException)
+++IndexOutOfBoundsException (extends RunTimeException)
+++... (etc)...

All standard checked-exception classes would be respecified to
extend CheckedException (which is simply an abstract marker class
that extends Exception).

The big problem with the above approach is existing
applications that define their own checked-exceptions
as extending from Exception. They would need a source
code change and recompile.
 
D

Dan Wilkin

xarax said:
/snip/

A possible approach is to add new exception,
java.lang.CheckedException, under Exception:

hierarchy:
Throwable
+---Error (extends Throwable)
+ Exception (extends Throwable)
++CheckedException (extends Exception)
+++IOException (extends CheckedException)
+++FileNotFoundException (extends CheckedException)
+++... (etc)...
++RunTimeException (extends Exception)
+++NullPointerException (extends RunTimeException)
+++IndexOutOfBoundsException (extends RunTimeException)
+++... (etc)...

All standard checked-exception classes would be respecified to
extend CheckedException (which is simply an abstract marker class
that extends Exception).

The big problem with the above approach is existing
applications that define their own checked-exceptions
as extending from Exception. They would need a source
code change and recompile.

A good approach, a new Exception subclass to handle only checked 'style'
exceptions. Thus Exception would neither be checked nor unchecked. It
would merely exist to signify the existence of an exception. Which begs
the question - why not get rid of it? Which brings us back to our
initial problem. Ultimately yes, I agree, this approach is inherently
flawed because it would require a rename and recompile of all existing code.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top