Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #31595 > unrolled thread

Abuse of AssertionError?

Started byEric Sosman <esosman@comcast-dot-net.invalid>
First post2015-04-21 08:44 -0400
Last post2015-04-21 17:05 +0200
Articles 7 — 4 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Abuse of AssertionError? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-04-21 08:44 -0400
    Re: Abuse of AssertionError? Jerry Stuckle <jstucklex@attglobal.net> - 2015-04-21 10:21 -0400
      Re: Abuse of AssertionError? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-04-21 11:21 -0400
        Re: Abuse of AssertionError? Jerry Stuckle <jstucklex@attglobal.net> - 2015-04-21 11:31 -0400
    Re: Abuse of AssertionError? j4n bur53 <janburse@fastmail.fm> - 2015-04-21 16:59 +0200
      Re: Abuse of AssertionError? Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-04-21 11:26 -0400
    Re: Abuse of AssertionError? Thomas Richter <thor@math.tu-berlin.de> - 2015-04-21 17:05 +0200

#31595 — Abuse of AssertionError?

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-04-21 08:44 -0400
SubjectAbuse of AssertionError?
Message-ID<mh5gl0$96t$1@dont-email.me>
     A recent thread on `assert' prompts me to ask for opinions
about something I've been doing that may not be entirely kosher.
Now and then I write a method that computes and returns a value,
but whose computation relies on a data structure built elsewhere.
If that data structure is messed up the computation may go off
the rails, and I'd like to detect that.

     For example, here's a (paraphrase of a) method that finds the
marginal income tax bracket for a stated income level:

	private static double marginalTaxRate(double income) {
	    income = Math.max(income, 0);
	    for (int i = BRACKETS.length; --i >= 0; ) {
	        if (income >= BRACKETS[i].floor) {
	            return BRACKETS[i].rate;
	        }
	    }
	    // What goes here?
	}

If everything has been set up correctly, the BRACKETS are arranged
in increasing order by their income floors and the floor of the
zero'th BRACKET is zero, so the `if' will eventually be satisfied
and the method will return a value.  But if something's amiss the
loop will run to completion -- and then the compiler will complain
about falling off the end of a value-returning method.

     My solution has been to write

	throw new AssertionError("BUG!");

where the comment stands, and I'd like others to comment on whether
this is an acceptable practice, or suggest a better approach.

     Red herrings that are of little interest:

     - Using `double' for monetary calculations.  I solemnly swear that
       in the context from which this example was adapted, `double' is
       an entirely suitable choice.  Sue me.

     - Rewriting the loop to remove the `i >= 0' test would silence
       the compiler's complaint.  But then if the BRACKETS were messed
       up I'd eventually get ArrayIndexOutOfBoundsException instead --
       even less informative than AssertionError, IMHO.

     Thoughts?  Ideas?

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [next] | [standalone]


#31596

FromJerry Stuckle <jstucklex@attglobal.net>
Date2015-04-21 10:21 -0400
Message-ID<mh5mbn$vju$1@dont-email.me>
In reply to#31595
On 4/21/2015 8:44 AM, Eric Sosman wrote:
> 
>     A recent thread on `assert' prompts me to ask for opinions
> about something I've been doing that may not be entirely kosher.
> Now and then I write a method that computes and returns a value,
> but whose computation relies on a data structure built elsewhere.
> If that data structure is messed up the computation may go off
> the rails, and I'd like to detect that.
> 
>     For example, here's a (paraphrase of a) method that finds the
> marginal income tax bracket for a stated income level:
> 
>     private static double marginalTaxRate(double income) {
>         income = Math.max(income, 0);
>         for (int i = BRACKETS.length; --i >= 0; ) {
>             if (income >= BRACKETS[i].floor) {
>                 return BRACKETS[i].rate;
>             }
>         }
>         // What goes here?
>     }
> 
> If everything has been set up correctly, the BRACKETS are arranged
> in increasing order by their income floors and the floor of the
> zero'th BRACKET is zero, so the `if' will eventually be satisfied
> and the method will return a value.  But if something's amiss the
> loop will run to completion -- and then the compiler will complain
> about falling off the end of a value-returning method.
> 
>     My solution has been to write
> 
>     throw new AssertionError("BUG!");
> 
> where the comment stands, and I'd like others to comment on whether
> this is an acceptable practice, or suggest a better approach.
> 
>     Red herrings that are of little interest:
> 
>     - Using `double' for monetary calculations.  I solemnly swear that
>       in the context from which this example was adapted, `double' is
>       an entirely suitable choice.  Sue me.
> 
>     - Rewriting the loop to remove the `i >= 0' test would silence
>       the compiler's complaint.  But then if the BRACKETS were messed
>       up I'd eventually get ArrayIndexOutOfBoundsException instead --
>       even less informative than AssertionError, IMHO.
> 
>     Thoughts?  Ideas?
> 

This is one way to do it, and I wouldn't say it's wrong.  But it doesn't
catch the error (a bad array) where it occurs; the code here may be a
long way from the code that created the array.

I would make a class Brackets.  In the constructor I would ensure the
array is created properly, then add a member such as

public double getRate(double income);

Then just call it with

  double rate = bracket.getRate(income);

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================

[toc] | [prev] | [next] | [standalone]


#31599

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-04-21 11:21 -0400
Message-ID<mh5psa$ee5$1@dont-email.me>
In reply to#31596
On 4/21/2015 10:21 AM, Jerry Stuckle wrote:
> On 4/21/2015 8:44 AM, Eric Sosman wrote:
>>
>>      A recent thread on `assert' prompts me to ask for opinions
>> about something I've been doing that may not be entirely kosher.
>> Now and then I write a method that computes and returns a value,
>> but whose computation relies on a data structure built elsewhere.
>> If that data structure is messed up the computation may go off
>> the rails, and I'd like to detect that.
>>
>>      For example, here's a (paraphrase of a) method that finds the
>> marginal income tax bracket for a stated income level:
>>
>>      private static double marginalTaxRate(double income) {
>>          income = Math.max(income, 0);
>>          for (int i = BRACKETS.length; --i >= 0; ) {
>>              if (income >= BRACKETS[i].floor) {
>>                  return BRACKETS[i].rate;
>>              }
>>          }
>>          // What goes here?
>>      }
>>
>> If everything has been set up correctly, the BRACKETS are arranged
>> in increasing order by their income floors and the floor of the
>> zero'th BRACKET is zero, so the `if' will eventually be satisfied
>> and the method will return a value.  But if something's amiss the
>> loop will run to completion -- and then the compiler will complain
>> about falling off the end of a value-returning method.
>>
>>      My solution has been to write
>>
>>      throw new AssertionError("BUG!");
>>
>> where the comment stands, and I'd like others to comment on whether
>> this is an acceptable practice, or suggest a better approach.
>>
>>      Red herrings that are of little interest:
>>
>>      - Using `double' for monetary calculations.  I solemnly swear that
>>        in the context from which this example was adapted, `double' is
>>        an entirely suitable choice.  Sue me.
>>
>>      - Rewriting the loop to remove the `i >= 0' test would silence
>>        the compiler's complaint.  But then if the BRACKETS were messed
>>        up I'd eventually get ArrayIndexOutOfBoundsException instead --
>>        even less informative than AssertionError, IMHO.
>>
>>      Thoughts?  Ideas?
>>
>
> This is one way to do it, and I wouldn't say it's wrong.  But it doesn't
> catch the error (a bad array) where it occurs; the code here may be a
> long way from the code that created the array.

     Thanks, Jerry.  In the particular program from which the example
was adapted, there's also an attempt to catch errors at the point where
the BRACKETS array is built.  Specifically, I've got something like

	static final Bracket[] BRACKETS = ...;
	static {
	    assert bracketsAreSane();
	}
	private static boolean bracketsAreSane() {
	    // assorted sanity checks here
	}

     However, this approach isn't always available.  For example, in
another program that uses Swing drag'n'drop operations I've got

	private static DataFlavor levelFlavor() {
	    try {
	        return new DataFlavor(
	            DataFlavor.javaJVMLocalObjectMimeType
                     + "; class=" + Level.class.getName());
	    } catch (ClassNotFoundException ex) {
	        throw new AssertionError("BUG! " + ex);
	    }
	}

Now, I "know" the DataFlavor constructor in this case isn't going to
throw up unless I misspelled something (e.g., "; clas="), so it seems
silly to force the caller to handle an exception that will "never"
occur.  To relieve the caller of the silly responsibility I've got to
write a `catch' block -- and what goes inside?

> I would make a class Brackets.  In the constructor I would ensure the
> array is created properly, then add a member such as
>
> public double getRate(double income);
>
> Then just call it with
>
>    double rate = bracket.getRate(income);

     Okay, but that just moves the problem back into the Brackets class,
which will have a loop similar to the one I showed.  Given the sanity
checks built into Brackets' constructor it might be defensible to write
an "infinite" loop to keep the compiler happy, b-u-u-t-...  It still
makes me queasy.

     Thanks for the comments.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#31601

FromJerry Stuckle <jstucklex@attglobal.net>
Date2015-04-21 11:31 -0400
Message-ID<mh5qfa$gio$1@dont-email.me>
In reply to#31599
On 4/21/2015 11:21 AM, Eric Sosman wrote:
> On 4/21/2015 10:21 AM, Jerry Stuckle wrote:
>> On 4/21/2015 8:44 AM, Eric Sosman wrote:
>>>
>>>      A recent thread on `assert' prompts me to ask for opinions
>>> about something I've been doing that may not be entirely kosher.
>>> Now and then I write a method that computes and returns a value,
>>> but whose computation relies on a data structure built elsewhere.
>>> If that data structure is messed up the computation may go off
>>> the rails, and I'd like to detect that.
>>>
>>>      For example, here's a (paraphrase of a) method that finds the
>>> marginal income tax bracket for a stated income level:
>>>
>>>      private static double marginalTaxRate(double income) {
>>>          income = Math.max(income, 0);
>>>          for (int i = BRACKETS.length; --i >= 0; ) {
>>>              if (income >= BRACKETS[i].floor) {
>>>                  return BRACKETS[i].rate;
>>>              }
>>>          }
>>>          // What goes here?
>>>      }
>>>
>>> If everything has been set up correctly, the BRACKETS are arranged
>>> in increasing order by their income floors and the floor of the
>>> zero'th BRACKET is zero, so the `if' will eventually be satisfied
>>> and the method will return a value.  But if something's amiss the
>>> loop will run to completion -- and then the compiler will complain
>>> about falling off the end of a value-returning method.
>>>
>>>      My solution has been to write
>>>
>>>      throw new AssertionError("BUG!");
>>>
>>> where the comment stands, and I'd like others to comment on whether
>>> this is an acceptable practice, or suggest a better approach.
>>>
>>>      Red herrings that are of little interest:
>>>
>>>      - Using `double' for monetary calculations.  I solemnly swear that
>>>        in the context from which this example was adapted, `double' is
>>>        an entirely suitable choice.  Sue me.
>>>
>>>      - Rewriting the loop to remove the `i >= 0' test would silence
>>>        the compiler's complaint.  But then if the BRACKETS were messed
>>>        up I'd eventually get ArrayIndexOutOfBoundsException instead --
>>>        even less informative than AssertionError, IMHO.
>>>
>>>      Thoughts?  Ideas?
>>>
>>
>> This is one way to do it, and I wouldn't say it's wrong.  But it doesn't
>> catch the error (a bad array) where it occurs; the code here may be a
>> long way from the code that created the array.
> 
>     Thanks, Jerry.  In the particular program from which the example
> was adapted, there's also an attempt to catch errors at the point where
> the BRACKETS array is built.  Specifically, I've got something like
> 
>     static final Bracket[] BRACKETS = ...;
>     static {
>         assert bracketsAreSane();
>     }
>     private static boolean bracketsAreSane() {
>         // assorted sanity checks here
>     }
> 
>     However, this approach isn't always available.  For example, in
> another program that uses Swing drag'n'drop operations I've got
> 
>     private static DataFlavor levelFlavor() {
>         try {
>             return new DataFlavor(
>                 DataFlavor.javaJVMLocalObjectMimeType
>                     + "; class=" + Level.class.getName());
>         } catch (ClassNotFoundException ex) {
>             throw new AssertionError("BUG! " + ex);
>         }
>     }
> 
> Now, I "know" the DataFlavor constructor in this case isn't going to
> throw up unless I misspelled something (e.g., "; clas="), so it seems
> silly to force the caller to handle an exception that will "never"
> occur.  To relieve the caller of the silly responsibility I've got to
> write a `catch' block -- and what goes inside?
> 
>> I would make a class Brackets.  In the constructor I would ensure the
>> array is created properly, then add a member such as
>>
>> public double getRate(double income);
>>
>> Then just call it with
>>
>>    double rate = bracket.getRate(income);
> 
>     Okay, but that just moves the problem back into the Brackets class,
> which will have a loop similar to the one I showed.  Given the sanity
> checks built into Brackets' constructor it might be defensible to write
> an "infinite" loop to keep the compiler happy, b-u-u-t-...  It still
> makes me queasy.
> 
>     Thanks for the comments.
> 

No, it doesn't "just move the problem back into the Brackets class".  It
also isolates the implementation of the array, and guarantees the array
is properly built before it can be used.  Then there is no possibility
of a failure.

And it's always better to find a problem when it occurs (i.e. when the
array is built), rather than much later when it is used.

And since you can now ensure the array is built properly, you could just
return a default value instead of throwing an exception.

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================

[toc] | [prev] | [next] | [standalone]


#31597

Fromj4n bur53 <janburse@fastmail.fm>
Date2015-04-21 16:59 +0200
Message-ID<mh5okk$jsi$1@news.albasani.net>
In reply to#31595
Eric Sosman schrieb:
>      My solution has been to write
>
>      throw new AssertionError("BUG!");

1) It depends on the context that runs the code.
For example sometimes I throw:

     throw new RuntimeException()

In such situation, and in my particular case
I know that the context will not catch it,
resulting probably in an application abort.

2) On the other hand sometimes I throw:

     throw new IllegalArgumentException();

But I don't need to declare this exception
either in the method signature. But it
could be that the context catches this.

3) Or sometimes I use an exception that is
clearly visible in the method signature,
and forces the context to act.

I guess you want scenario 1) ?

[toc] | [prev] | [next] | [standalone]


#31600

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-04-21 11:26 -0400
Message-ID<mh5q67$fkl$1@dont-email.me>
In reply to#31597
On 4/21/2015 10:59 AM, j4n bur53 wrote:
> Eric Sosman schrieb:
>>      My solution has been to write
>>
>>      throw new AssertionError("BUG!");
>
> 1) It depends on the context that runs the code.
> For example sometimes I throw:
>
>      throw new RuntimeException()
>
> In such situation, and in my particular case
> I know that the context will not catch it,
> resulting probably in an application abort.
>
> 2) On the other hand sometimes I throw:
>
>      throw new IllegalArgumentException();
>
> But I don't need to declare this exception
> either in the method signature. But it
> could be that the context catches this.
>
> 3) Or sometimes I use an exception that is
> clearly visible in the method signature,
> and forces the context to act.
>
> I guess you want scenario 1) ?

     Thanks for the comments.  I use (3) when the problem is actually
expected to occur and the caller may want to do something about it,
and I use (2) when the problem truly stems from bad arguments rather
than bad "environment."  But when the problem isn't the caller's
fault and "shouldn't happen" to begin with, I'll go for (1) in some
form.  Sometimes IllegalStateException makes sense, but if it doesn't
I think AssertionError("BUG!") is perhaps a bit more descriptive than
a raw RuntimeException.  But I'll consider RuntimeException("BUG!")
as an alternative, if AssertionError seems too much like an abuse.

     Thanks again.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#31598

FromThomas Richter <thor@math.tu-berlin.de>
Date2015-04-21 17:05 +0200
Message-ID<mh5ovf$dh8$1@news2.informatik.uni-stuttgart.de>
In reply to#31595
Am 21.04.2015 um 14:44 schrieb Eric Sosman:
> 

> 
>     For example, here's a (paraphrase of a) method that finds the
> marginal income tax bracket for a stated income level:
> 
>     private static double marginalTaxRate(double income) {
>         income = Math.max(income, 0);
>         for (int i = BRACKETS.length; --i >= 0; ) {
>             if (income >= BRACKETS[i].floor) {
>                 return BRACKETS[i].rate;
>             }
>         }
>         // What goes here?
>     }
> 
> If everything has been set up correctly, the BRACKETS are arranged
> in increasing order by their income floors and the floor of the
> zero'th BRACKET is zero, so the `if' will eventually be satisfied
> and the method will return a value.  But if something's amiss the
> loop will run to completion -- and then the compiler will complain
> about falling off the end of a value-returning method.
> 
>     My solution has been to write
> 
>     throw new AssertionError("BUG!");
> 
> where the comment stands, and I'd like others to comment on whether
> this is an acceptable practice, or suggest a better approach.

Actually, I don't quite see what's wrong with that. I would have done
pretty much the same. asserts() are used to catch program errors that
require fixing the software if the program runs into them. Exceptions
and throw are not quite the right mechanism for that; their purpose is
more to allow the program to "fix" the problem by software at run time.
That does not seem to be given here.

Greetings,
	Thomas

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web