The Artima Developer Community
Sponsored Link

Weblogs Forum
What's Your ShouldNeverHappenException?

73 replies on 5 pages. Most recent reply: Jan 26, 2007 9:01 PM by Gregg Wonderly

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 73 replies on 5 pages [ « | 1 2 3 4 5 | » ]
James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 9:34 AM
Reply to this message Reply
Advertisement
> > I don't need to reread it.
>
> Why am I talking to you then?

Because we are having a conversation.

> Oh, yeah, you can read my mind.

I don't see how not needing to re-reading something makes me a mind-reader. Are you updating the thread with your thoughts? I'm completely baffled by this comment.

> As usual James, (I've seen this happen in countless other
> Artima discussions) you refuse to read and listen to other
> people on this list and then claim to understand their
> thoughts.

I have no idea what you are talking about here. I asked you some questions. The whole point is for you to tell me what you are thinking. If there is a flaw in my logic, point it out. No need for personal attacks.

I've read what you have written very carefully. Did I misrepresent your position? If so, tell me how.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 10:15 AM
Reply to this message Reply
> Please reread the original post. A Checked Exception has
> been thrown. You can either delcare that you throw it,
> annoying an call stack, call System.exit(), log it and do
> nothing, which I feel is awful, or wrap it in some
> unchecked exception. As the original poster said, best
> practice is to wrap in some unchecked exception.

I really can't see how my not needing to reread the original post means I'm 'reading your mind'. As you say, the original post says to thrown an unchecked exception. That's exactly what I am saying to do? How is reading something that I fully agree with going to illuminate your argument given that you are contradicting the advice in the original post? Please, I want to understand.

David Beutel

Posts: 29
Nickname: jdb
Registered: May, 2003

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 11:44 AM
Reply to this message Reply
I also think an Error should be thrown in the given example, and java.lang.AssertionError is the most appropriate (not to be confused with junit.framework.AssertionFailedError), unless you want to make up your own (e.g., ImpossibleError).

Java's API spec says "Every implementation of the Java platform is required to support the following standard charsets." UTF-8 is on that list.

http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html

So if URLEncoder says it's not supported then that JVM is broken. And since, unfortunately, the API provides no way to avoid handling that checked Exception (such as by using a Charset, like OutputStreamWriter), the program is forced to handle it. Throwing an Error is the best way to handle a broken JVM.

Even though the program shouldn't try to recover from an Error, it should still try to handle them (e.g., logging them) along with RuntimeExceptions in its last-ditch catch, if it has one.

The assertion issue in general is complex, but the example at hand is clearly an Error.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 12:07 PM
Reply to this message Reply
> I also think an Error should be thrown in the given
> example, and java.lang.AssertionError is the most
> appropriate (not to be confused with
> junit.framework.AssertionFailedError), unless you want to
> make up your own (e.g., ImpossibleError).
>
> Java's API spec says "Every implementation of the Java
> platform is required to support the following standard
> charsets." UTF-8 is on that list.
>
> http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Ch
> arset.html
>
> So if URLEncoder says it's not supported then that JVM is
> broken. And since, unfortunately, the API provides no way
> to avoid handling that checked Exception (such as by using
> a Charset, like OutputStreamWriter), the program is forced
> to handle it. Throwing an Error is the best way to handle
> a broken JVM.

You (and others) say Error is the best way to handle 'a broken JVM' but you don't explain why. What is the reasoning behind this statement.

It seems to me that the most likely scenarios for this exception being thrown is that the code is changed to use other charsets but the catch block was not updated or the code that is reporting the UnsupportedEncodingException has a bug in it.

I'm not convinced it's a good idea for a typical Java application to say the JVM is broken. I think that it's up to the JVM to report if it's broken. In any event, even if the JVM is broken, what advantage is there to turning an Exception into an Error?

> Even though the program shouldn't try to recover from an
> Error, it should still try to handle them (e.g., logging
> them) along with RuntimeExceptions in its last-ditch
> catch, if it has one.

Sure but that's minimal error handling. I do a lot more than that for Exceptions.

> The assertion issue in general is complex, but the example
> at hand is clearly an Error.

You are assuming the only thing that can cause this is a virtual machine error. That's not the case.

David Beutel

Posts: 29
Nickname: jdb
Registered: May, 2003

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 12:53 PM
Reply to this message Reply
> It seems to me that the most likely scenarios for this
> exception being thrown is that the code is changed to use
> other charsets but the catch block was not updated or the
> code that is reporting the UnsupportedEncodingException
> has a bug in it.

If you suppose that someone in the future changes this code and introduces a bug, then the AssertionError would still be better than a RuntimeException. It tells more about the nature of the bug.

> I'm not convinced it's a good idea for a typical Java
> application to say the JVM is broken. I think that it's
> up to the JVM to report if it's broken. In any event,
> even if the JVM is broken, what advantage is there to
> turning an Exception into an Error?

If the application knows that its Java platform is broken, then it should say so. Either the platform really is broken, or the application is wrong about it (i.e., has a bug). The Error communicates this better than a RuntimeException. A RuntimeException does not necessarily indicate a broken platform or bug, and a program might want to recover from it in some situations (e.g., NumberFormatException).

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 1:24 PM
Reply to this message Reply
> > It seems to me that the most likely scenarios for this
> > exception being thrown is that the code is changed to
> use
> > other charsets but the catch block was not updated or
> the
> > code that is reporting the UnsupportedEncodingException
> > has a bug in it.
>
> If you suppose that someone in the future changes this
> code and introduces a bug, then the AssertionError would
> still be better than a RuntimeException. It tells more
> about the nature of the bug.

How? What extra information does it give me?

> > I'm not convinced it's a good idea for a typical Java
> > application to say the JVM is broken. I think that
> it's
> > up to the JVM to report if it's broken. In any event,
> > even if the JVM is broken, what advantage is there to
> > turning an Exception into an Error?
>
> If the application knows that its Java platform is broken,
> then it should say so.

If you can show me some evidence (documentation, etc.) that only a JVM failure can cause this to happen, then I might be convinced. Otherwise, I think it's 'chicken little' exception handling.

I'm almost convinced that an Error is acceptable here except that I so absolutely no advantage to

> Either the platform really is
> broken, or the application is wrong about it (i.e., has a
> bug). The Error communicates this better than a
> RuntimeException.

In what way?

> A RuntimeException does not necessarily
> indicate a broken platform or bug, and a program might
> want to recover from it in some situations (e.g.,
> NumberFormatException).

If your intention is to recover from NumberFormatException, you should be catching NumberFormatException not RuntimeException or Exception.

What makes you so sure that this is not recoverable? Suppose you are writing library to be used by other teams' applications. You throw an Error if this happens. Something crazy occurs and it does. Their code squashes any Exceptions from the call to your library because for their application, it's not critical if the call to your library blew-up, it's more important that the app continue. They just log the exception and continue. So your code throws an Error and circumvents their intent. I don't think it's a good thing for code to force calling code to crash based on the presumptions of the developer.

Morgan Conrad

Posts: 307
Nickname: miata71
Registered: Mar, 2006

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 4:48 PM
Reply to this message Reply
> The Error communicates this better than a
> > RuntimeException.
>
> In what way?

James, in what way does RuntimeException communicate "hey, this is really serious" better than, er, RuntimeException? It doesn't. Error is more "serious".

> NumberFormatException, you should be catching
> NumberFormatException not RuntimeException or Exception.

I've seen to much code where somewhere along the call stack somebody catches all RuntimeExceptions, logs them, (maybe then wraps them in something else) and continues. Which is why, in our opinions, Error is better - less likely to get ignored.


> I don't think it's a good thing for code to
> force calling code to crash based on the presumptions of
> the developer.

First you complain that Error does not communicate that it's a serious problem any better than RuntimeException. Then here you complain that Error is more serious. Clearly it does communicate better!

David Beutel

Posts: 29
Nickname: jdb
Registered: May, 2003

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 5:41 PM
Reply to this message Reply
> > If the application knows that its Java platform is
> broken,
> > then it should say so.
>
> If you can show me some evidence (documentation, etc.)
> that only a JVM failure can cause this to happen, then I
> might be convinced. Otherwise, I think it's 'chicken
> little' exception handling.

I quoted that documentation in the first place:

Java's API spec says, "Every implementation of the Java platform is required to support the following standard charsets." UTF-8 is on that list.

http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html

So if URLEncoder.encode(url, "UTF-8") throws UnsupportedEncodingException then the program knows that its Java platform does not meet the requirements of the Java API spec. I don't know what else the program could reasonably assume in that situation.

It's a weakness in the API, frankly, that it provides no way to avoid this impossible checked exception. I think some exceptions should be checked, but this example lends support to the faction who think no exceptions should be checked. The best we can do is clearly distinguish what we know is impossible, close to the source and without spreading ugly code.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 5:48 PM
Reply to this message Reply
> > The Error communicates this better than a
> > > RuntimeException.
> >
> > In what way?
>
> James, in what way does RuntimeException communicate "hey,
> this is really serious" better than, er, RuntimeException?
> It doesn't. Error is more "serious".

Yes, Error is more serious which is exactly why people shouldn't catch it. I never said that Error isn't more serious than RuntimeException. I'm saying that the original Exception doesn't imply an Error. Again, how is an incorrect assumption by a developer equivalent to a JVM failure? Do you believe NullPointerException should be an Error class? Let me be more specific: what if there's 'no way' the pointer could be null?

> > NumberFormatException, you should be catching
> > NumberFormatException not RuntimeException or
> Exception.
>
> I've seen to much code where somewhere along the call
> stack somebody catches all RuntimeExceptions, logs them,
> (maybe then wraps them in something else) and continues.
> Which is why, in our opinions, Error is better - less
> s likely to get ignored.

That's bad practice. I don't think more bad practices will make things better.

> > I don't think it's a good thing for code to
> > force calling code to crash based on the presumptions
> of
> > the developer.
>
> First you complain that Error does not communicate that
> it's a serious problem any better than RuntimeException.
> Then here you complain that Error is more serious.
> . Clearly it does communicate better!

It communicates the wrong thing. How is that better?

An undocumented RuntimeException is a serious error. How serious depends on context. You are deciding for the callers how serious the issue is. If they are just ignoring the RuntimeException, that's their problem. I've seen people catch and ignore Throwable. There's little you can do to save people from themselves. You are making a huge presumption that a crash is the proper thing to do. Sometimes it's absolutely the correct thing to log and continue. For example, if the code is trying to load an optional logging configuration. You can make a case under circumstances that throwing an Error is the right choice but to say that anytime something you considered impossible occurs seems absolutely irresponsible. It will make people question not catching Error. I do it already. After this conversation I'm very unsure that when I absolutely need something to continue after an operation unless the JVM is crashing that I'm OK just catching Exception.

Consider the following:
public void setMessage(byte[] bytes) 
{
    try {
        message = new String(bytes, encoding);
    } catch (UnsupportedEncodingException e){
        throw new RuntimeException(e);
    }
}


Where encoding is loaded from an configuration file. Do you think there should be check to see if encoding is one of those required by the JLS and if it is, throw an Error instead?

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 6:10 PM
Reply to this message Reply
> > > If the application knows that its Java platform is
> > broken,
> > > then it should say so.
> >
> > If you can show me some evidence (documentation, etc.)
> > that only a JVM failure can cause this to happen, then
> I
> > might be convinced. Otherwise, I think it's 'chicken
> > little' exception handling.
>
> I quoted that documentation in the first place:
>
> Java's API spec says, "Every implementation of the Java
> platform is required to support the following standard
> charsets." UTF-8 is on that list.
> http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Ch
> arset.html

That doesn't mention anything about UnsupportedEncodingException. All it says is that JVMs are supposed to support those encodings no matter what. And of course we all know that there are no JVMs out there that don't implement the JLS 100% correctly, right?

> So if URLEncoder.encode(url, "UTF-8") throws
> UnsupportedEncodingException then the program knows that
> its Java platform does not meet the requirements of the
> Java API spec.

Assuming that the code is correct. Why do you assume that?

> I don't know what else the program could
> reasonably assume in that situation.

Why does it need to assume anything? Why not just do what it would do when anything else goes wrong?

If I did this:

final String s = "a string";
try {
   s.equals(someString);
} catch (NullPointerException e) {
   throw new AssertionError("there's no way s can be null");
}


You'd think I was daft. But is it really different from what you are advocating? The only difference is that we aren't forced to catch the NullPointerException. But if 'impossible' events should result in Errors, why wouldn't the above make sense? If s is null, there's definitely something wrong in the VM (unless of course someone came along and modified the code). Isn't just letting the NullPointerException fall out as a normal NullPointerException wrong here, according to your view?

> It's a weakness in the API, frankly, that it provides no
> way to avoid this impossible checked exception. I think
> some exceptions should be checked, but this example lends
> support to the faction who think no exceptions should be
> checked. The best we can do is clearly distinguish what
> we know is impossible, close to the source and without
> spreading ugly code.

But if this were unchecked, you wouldn't catch it and re-throw it as an Error, right?

David Beutel

Posts: 29
Nickname: jdb
Registered: May, 2003

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 7:18 PM
Reply to this message Reply
> But if this were unchecked, you wouldn't catch it and
> re-throw it as an Error, right?

Right. We shouldn't catch an impossible RuntimeException and re-throw it as an Error, because there are too many impossibilities and it would clutter up the code. It's only because the compiler forced us to handle the checked exception, and in that particular piece of code it would mean that its Java platform has a bug.

I'm not suggesting that UnsupportedEncodingException should be unchecked. The API doesn't know what's inside that String. Actually, I think Charset should have static instances for UTF8 and the other encodings that are required of all Java platforms, and all the APIs that take a charsetName String should also have a method that takes a Charset without throwing UnsupportedEncodingException (like OutputStreamWriter does).

Morgan Conrad

Posts: 307
Nickname: miata71
Registered: Mar, 2006

Re: What's Your ShouldNeverHappenException? Posted: Jan 18, 2007 8:10 PM
Reply to this message Reply
> Yes, Error is more serious which is exactly why people
> shouldn't catch it.

Why should they not catch it? You are making the totally religious argument that you should never catch Error. This is NOT supported by the javadocs you have cited.

> Do you believe NullPointerException should be an
> Error class?

Usually not. But if Runtime.getRunTime() returns null, and I know that our code uses Runtime.getRuntime() a lot for an essential function, then that's an Error.


> > I've seen to much code where somewhere along the call
> > stack somebody catches all RuntimeExceptions,

> That's bad practice. I don't think more bad practices
> will make things better.

I agree it's bad. But I'm practical.


> It communicates the wrong thing. How is that better?

What is wrong? "serious problems that a reasonable application should not try to catch... should never occur".

Sounds right to me. The last three words - hey, they match the name of this thread!



> For example, if the code is trying to load an
> optional logging configuration.

Agreed. But irrelevant. Nobody has proposed throwing Error if an optional thing fails! I explicitly said that this is not a case to throw Error. Please, please stop spouting off nonsense. If we are having a discussion, as you argue, you must read our posts. Since you aren't, I'm signing off.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 19, 2007 7:31 AM
Reply to this message Reply
> > Yes, Error is more serious which is exactly why people
> > shouldn't catch it.
>
> Why should they not catch it? You are making the totally
> religious argument that you should never catch Error.
> This is NOT supported by the javadocs you have cited.

How do you interpret this statement, then?

"An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch."

> > Do you believe NullPointerException should be an
> > Error class?
>
> Usually not. But if Runtime.getRunTime() returns null,
> and I know that our code uses Runtime.getRuntime() a lot
> for an essential function, then that's an Error.
>
>
> > > I've seen to much code where somewhere along the call
> > > stack somebody catches all RuntimeExceptions,
>
> > That's bad practice. I don't think more bad practices
> > will make things better.
>
> I agree it's bad. But I'm practical.

If people are squashing exceptions, and you start throwing Errors to overcome that issue, how long will it be before these same people start squashing Error? It's a slippery slope. An arms race is not the solution.

> > It communicates the wrong thing. How is that better?
>
> What is wrong? "serious problems that a reasonable
> application should not try to catch... should never
> occur".
>
> Sounds right to me. The last three words - hey, they
> match the name of this thread!

It communicates that the JVM is foundering and that the code should not try to recover or handle the issue like it would an Exception. But in a lot of cases this is very questionable.

> > For example, if the code is trying to load an
> > optional logging configuration.
>
> Agreed. But irrelevant. Nobody has proposed throwing
> Error if an optional thing fails! I explicitly said that
> this is not a case to throw Error.

Again, you are missing the point. If you are writing an API that someone else is using, how do you know whether the call to your library is part of an optional operation? If you throw Error you are assuming it is not. Is this not the kind code you said you write?

> Please, please stop
> spouting off nonsense. If we are having a discussion, as
> you argue, you must read our posts. Since you aren't, I'm
> signing off.

I think it is you who refuses to read and understand what I am saying. I don't know why you are making this into some sort of holy war. I'm considering your points and I'm even convinced that in some cases that you could make a good case for throwing Error. My point is that just because something was unexpected doesn't make it fatal. Whether you throw an Error or not should be related to the severity of the problem, not the developers expectation of the likely-hood of it's occurrence.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: What's Your ShouldNeverHappenException? Posted: Jan 19, 2007 9:17 AM
Reply to this message Reply
> > But if this were unchecked, you wouldn't catch it and
> > re-throw it as an Error, right?
>
> Right. We shouldn't catch an impossible RuntimeException
> and re-throw it as an Error, because there are too many
> impossibilities and it would clutter up the code.

OK, now we are getting somewhere. Here's what I am saying about this. Clearly, it's acceptable that some 'impossible' exceptions are handled as RuntimeExceptions. Therefore, it is not crucial that 'impossible' exceptions are handled as Errors. But you are saying that they should be at least sometimes. The question I have is what is the determining factor. This, as I understand it, is your answer to the question.

> It's
> only because the compiler forced us to handle the checked
> exception, and in that particular piece of code it would
> mean that its Java platform has a bug.

I can't agree with this. For one, whether the exception was checked or not doesn't have any direct relationship with whether the platform has a bug. Making this be the determining factor is completely arbitrary. For example, there was a bug in the initial version of 1.4 (IIRC) with hotspot optimization that was causing NullPointerException (or some other RuntimeException) to be thrown from code that, per the JLS, could not throw such an exception. It cannot be the case that only checked exceptions are related to JVM failures. Your statement above, if taken literally is demonstrably untrue.

Even so, if we take the code I posted above that accepts a byte array and an encoding, it's clearly the case that sometimes the encoding could be UTF-8 or any of the other required encodings. But the way the code is structured, a failure with UTF-8 would be handled as a RuntimeException, not an Error. If you don't believe that code should handle the required encodings specially and throw Errors for these encodings, then in one case we are saying a failure to encode with UTF-8 is an Error but in another case we are saying it's an Exception. Why? The exact same operation is be executed. The only difference is whether we are hardcoding the encoding.

Beyond being inconsistent, the final result, from the perspective of the operation is merely that the bytes could not be translated to a String whether the encoding was hardcoded or dynamically supplied, UTF-8 or EBCDIC. That's all that has occurred. To say that this means the JVM must exit in this case is to me a huge leap given that I can think of a lot of situations where that would not be desireable.

David Beutel

Posts: 29
Nickname: jdb
Registered: May, 2003

Re: What's Your ShouldNeverHappenException? Posted: Jan 19, 2007 12:07 PM
Reply to this message Reply
> > It's
> > only because the compiler forced us to handle the
> checked
> > exception, and in that particular piece of code it
> would
> > mean that its Java platform has a bug.
>
> I can't agree with this. For one, whether the exception
> was checked or not doesn't have any direct relationship
> with whether the platform has a bug. Making this be the
> determining factor is completely arbitrary. For example,
> there was a bug in the initial version of 1.4 (IIRC) with
> hotspot optimization that was causing NullPointerException
> (or some other RuntimeException) to be thrown from code
> that, per the JLS, could not throw such an exception. It
> cannot be the case that only checked exceptions are
> related to JVM failures. Your statement above, if taken
> literally is demonstrably untrue.

The goal is not to test for and handle bugs in the platform. The program must assume that the platform is working properly, not try to handle bugs in it. The goal is to handle the checked exception, because the compiler forces the program to handle it. And in that particular situation, passing a constant or literal "UTF-8" as an encoding to a core Java API, that part of the program knows that if that one call throws an UnsupportedEncodingException then the platform has a bug. The program wasn't looking for a bug in the platform, but unfortunately the compiler forced it to handle a bug in the platform, so at that point all bets are off and throwing an Error is the best that code can do.

> Even so, if we take the code I posted above that accepts a
> byte array and an encoding, it's clearly the case that
> sometimes the encoding could be UTF-8 or any of the other
> required encodings. But the way the code is structured, a
> failure with UTF-8 would be handled as a RuntimeException,
> not an Error. If you don't believe that code should
> handle the required encodings specially and throw Errors
> for these encodings, then in one case we are saying a
> failure to encode with UTF-8 is an Error but in another
> case we are saying it's an Exception. Why? The exact
> same operation is be executed. The only difference is
> whether we are hardcoding the encoding.

That difference is key. In the following code, an error in the platform (or bug in the code, e.g., "UTF8") is the only possibility, regardless of what's outside this code.

public static String encodeUrlInUtf8(URL url) {
try {
return URLEncoder.encode(url, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
}

If you widen the scope by making the encoding some kind of parameter, then the exception should be handled differently, because it's no longer so impossible. If it's a public library method, e.g., part of a Facade on the core API, then I would make the caller handle the checked exception:

public static String encodeUrlFacade(URL url, String encoding) throws UnsupportedEncodingException {
return URLEncoder.encode(url, encoding);
}

If it's a private method, then I might look at how it's called and still be able to assert the impossibility within the method. This has more risk of future bugs, though, because the locations of the encoding names are farther away from the assertion. So I would try to minimize the scope instead.

If the code is using a configuration parameter, I might throw a ConfigurationException extends RuntimeException. If a user typed the encoding name as input, I would validate it instead of throwing an exception (and then assert that the validated encoding is supported).

In any case, I would not go looking for platform bugs by writing code to check whether the encoding name String is one of those required to be supported by all Java platforms (and throwing an Error in that case). That would unnecessarily complicate the code. It would not be worth it.

The key issue here is what is impossible. What does impossible mean? What should the code assume and not try to handle? It depends on what scope the programmer is considering. The larger the scope, the more complexity and bugs.

Flat View: This topic has 73 replies on 5 pages [ « | 1  2  3  4  5 | » ]
Topic: What's Your ShouldNeverHappenException? Previous Topic   Next Topic Topic: C++ Delegation and Dynamic Inheritance

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use