Java language and library suggestions

A

Arne Vajhøj

Tomas said:
Then one would not use the proposed @safe directive in that case. I
didn't suggest to use it any time it seems that the code does not
throw exceptions.
Anyway there are still many cases when one could use safely it to get
more readable code.

It can happen, but I don't think it occur frequently enough to
justify a feature that is so easy to misuse.

Arne
 
T

Tomas Mikula

It can happen, but I don't think it occur frequently enough to
justify a feature that is so easy to misuse.

Arne

I disagree again. Almost everything can be misused. If someone feels
like their code never throws an exception, they could tend to write an
empty exception handler:

try {
// code that is incorrectly assumed not to throw any exception
} catch(Exception e) { }

If the Exception can actually be thrown and should be handled, this is
very bad.
I guess that the following would be a much better (although still bad)
solution in this case.

@safe
// code that is incorrectly assumed not to throw any exception

So even if it's going to be misused, it could eventually restrain from
worse things.

Tomas

Tomas
 
L

Lew

Tomas said:
I disagree again. Almost everything can be misused. If someone feels
like their code never throws an exception, they could tend to write an
empty exception handler:

try {
// code that is incorrectly assumed not to throw any exception
} catch(Exception e) { }

If the Exception can actually be thrown and should be handled, this is
very bad.
I guess that the following would be a much better (although still bad)
solution in this case.

@safe
// code that is incorrectly assumed not to throw any exception

So even if it's going to be misused, it could eventually restrain from
worse things.

"could" != "would".

The proposed language feature would be a change to the language that would be
easy to misuse, might just possibly (if you're right) help ever-so-slightly in
some corner cases, in order to save a little bit of typing. It doesn't seem
like a good tradeoff. Just write the damn exception handler and quit complaining.
 
T

Tom Anderson

For the vast majority of exceptions, this is true. The problem is that
there are a small number of checked-exception-throwing expression where it
is not true. Constructing a URL from a known-good literal string is one;
constructing an InputStreamReader with a known-good charset name (eg
UTF-8, which the spec always requires to be available) is another. In both
those cases, i would say that providing a bad URL or a bad charset name is
a programmer error, and thus the kind of thing that should get a runtime
exception, not a checked exception.

Rather than taking that as an argument for an @safe construct (@assert is
a terrible name for it, by the way, so let's keep calling it @safe -
@AssertSafe would perhaps be even better), i think it's an argument that
the library design is wrong - those methods should be throwing runtime
exceptions, not checked exceptions.

The problem, of course, is that the same methods are also used with
not-known-good values for URLs and charsets which come from outside the
source code, and thus are vulnerable to not-programmer-error failure,
which should elicit a checked exception after all.

Perhaps we should just declare that it's the programmer's job to check the
arguments, and use runtime exceptions anyway.

Perhaps there should be two variants of each of these methods, one which
throws a checked exception and one which doesn't. Except then you just
know that programmers will call the version without the checked exception
even with external parameters, and we're back to just having an unchecked
version.

Maybe literal strings should have a different type to strings that came
from data. Perhaps something like smalltalk's 'symbol', except that there
would be no way to make a symbol from a string. There could be a version
of the method which took a string and threw a checked exception, and a
version which took a symbol and didn't. This is obviously getting a bit
mental, though.

As far as the InputStreamReader example is concerned, a more OO solution
would be to use the version of the constructor which takes a Charset
rather than a charset name, which doesn't throw an exception - if you have
a Charset object, then you know you have a valid charset, so there's no
need. You can get a Charset object from Charset.forName without having to
deal with a checked exception - i think you shouldn't be able to, but you
can. Why there aren't constants on Charset for the six standard charsets,
i really don't know.

I can't think of an equivalent to this for creating URLs. It's not as if
you can have constants for all valid URLs, is it? You could add a constant
to your own class for the URL in question, but you still get a
MalformedURLException in defining it. This is where Tomas's idea comes in
useful:

@AssertSafe(MalformedURLException.class)
public static final URL u = new URL("http://www.example.com/");

I'm not sure if you can do that with an annotation - suppressing an error
rather than a warning? - but we want something along those lines. Maybe it
should be some harder bit of syntax, although i can't see a suitable
keyword, and i'd be loath to add a new one.
That doesn't change anything. Maybe I chose a misleading name. Maybe I
should have chosen @assert instead of @safe.
Then
@assert any_statement;
means that I make an assertion that any_statement will not throw any
exception. And if it does, it is an AssertionError.
And if the semantics of any_statement changes in the future, it's
still an AssertionError.
Consider the example:

int i;
try {
i = Integer.parseInt(valid_int_string);
} catch(NumberFormatException e) {
throw new AssertionError(e);
}

What you say means that I should not throw AssertionError, because in
the future the code could really throw the NumberFormatException. But
if it does, I still want to get the AssertionError, because
continueing without the correct value in i does not have any sense.

Since NumberFormatException is a runtime exception, this is a bad example.

tom
 
T

Tom Anderson

"could" != "would".

The proposed language feature would be a change to the language that
would be easy to misuse, might just possibly (if you're right) help
ever-so-slightly in some corner cases, in order to save a little bit of
typing. It doesn't seem like a good tradeoff. Just write the damn
exception handler and quit complaining.

This *is* an exception handler! It's shorthand for:

try {
STATEMENT
}
catch (EXCEPTION e) {
throw new AssertionError(e);
}

How is that not an exception handler?

Given that the most common damn exception handler the typical programmer
would write after quitting complaining would be:

try {
STATEMENT
}
catch (EXCEPTION e) {} // good luck debugging this

Giving them an easier syntax that does something more sensible is going to
make things better, not worse.

I know that you'd like everyone to write proper exception handling - so
would i, so would we all - it's never going to happen, so if you pull your
head out of the sand and think about java as she is spoke and writ in
reality, this looks like a reasonable idea.

tom
 
A

Arne Vajhøj

Tom said:
This *is* an exception handler! It's shorthand for:

try {
STATEMENT
}
catch (EXCEPTION e) {
throw new AssertionError(e);
}

How is that not an exception handler?

It is an exception handler.

But it is converting the exception that the designer of the API
being called consider a real possibility to an exception that should
never happen by the designer of the calling code.

That is a pretty serious decision. It makes sense to me that it
requires some rather explicit coding.
Given that the most common damn exception handler the typical programmer
would write after quitting complaining would be:

try {
STATEMENT
}
catch (EXCEPTION e) {} // good luck debugging this

We need to decide whether we want to design Java after
making it easy for college students in the first months
of programming or whether we want to design a language
for real usage.

That construct should never be seen in real usage.

If it does, then the problem is not in the Java syntax
but 40 cm's in front of the keyboard.
I know that you'd like everyone to write proper exception handling - so
would i, so would we all - it's never going to happen, so if you pull
your head out of the sand and think about java as she is spoke and writ
in reality, this looks like a reasonable idea.

Actually I believe that somewhere between some and good
exception handling is the norm.

Arne
 
A

Arne Vajhøj

Tomas said:
I disagree again. Almost everything can be misused.

Yes.

But that does not justify adding a feature to the language that is easy
to misuse and has little benefits.
If someone feels
like their code never throws an exception, they could tend to write an
empty exception handler:

try {
// code that is incorrectly assumed not to throw any exception
} catch(Exception e) { }

Hopefully no one writing Java code for a living.
If the Exception can actually be thrown and should be handled, this is
very bad.
I guess that the following would be a much better (although still bad)
solution in this case.

@safe
// code that is incorrectly assumed not to throw any exception

So even if it's going to be misused, it could eventually restrain from
worse things.

They could also just write the proper exception handler.

Arne
 
A

Arne Vajhøj

Tom said:
For the vast majority of exceptions, this is true. The problem is that
there are a small number of checked-exception-throwing expression where
it is not true. Constructing a URL from a known-good literal string is
one; constructing an InputStreamReader with a known-good charset name
(eg UTF-8, which the spec always requires to be available) is another.
In both those cases, i would say that providing a bad URL or a bad
charset name is a programmer error, and thus the kind of thing that
should get a runtime exception, not a checked exception.

Rather than taking that as an argument for an @safe construct (@assert
is a terrible name for it, by the way, so let's keep calling it @safe -
@AssertSafe would perhaps be even better), i think it's an argument that
the library design is wrong - those methods should be throwing runtime
exceptions, not checked exceptions.

The problem, of course, is that the same methods are also used with
not-known-good values for URLs and charsets which come from outside the
source code, and thus are vulnerable to not-programmer-error failure,
which should elicit a checked exception after all.

Perhaps we should just declare that it's the programmer's job to check
the arguments, and use runtime exceptions anyway.

Perhaps there should be two variants of each of these methods, one which
throws a checked exception and one which doesn't. Except then you just
know that programmers will call the version without the checked
exception even with external parameters, and we're back to just having
an unchecked version.

Maybe literal strings should have a different type to strings that came
from data. Perhaps something like smalltalk's 'symbol', except that
there would be no way to make a symbol from a string. There could be a
version of the method which took a string and threw a checked exception,
and a version which took a symbol and didn't. This is obviously getting
a bit mental, though.

As far as the InputStreamReader example is concerned, a more OO solution
would be to use the version of the constructor which takes a Charset
rather than a charset name, which doesn't throw an exception - if you
have a Charset object, then you know you have a valid charset, so
there's no need. You can get a Charset object from Charset.forName
without having to deal with a checked exception - i think you shouldn't
be able to, but you can. Why there aren't constants on Charset for the
six standard charsets, i really don't know.

I can't think of an equivalent to this for creating URLs. It's not as if
you can have constants for all valid URLs, is it? You could add a
constant to your own class for the URL in question, but you still get a
MalformedURLException in defining it. This is where Tomas's idea comes
in useful:

@AssertSafe(MalformedURLException.class)
public static final URL u = new URL("http://www.example.com/");

I'm not sure if you can do that with an annotation - suppressing an
error rather than a warning? - but we want something along those lines.
Maybe it should be some harder bit of syntax, although i can't see a
suitable keyword, and i'd be loath to add a new one.

There are such cases.

But how many of these cases do you know for sure will never
be refactored?

You start with a literal in the code, then it gets refactored as
a constant and later it becomes an argument to the constructor.

Arne
 
T

Tomas Mikula

Thank everyone for the opinions. I thought that @safe was something
everyone would like to have. But I see it didn't get much acceptance.
Still none of the arguments presented so far has convinced me that
it's a bad idea to have this in the language. But I would be happy
with more powerful annotations that would allow to change the code
being annotated at compile time.

Since NumberFormatException is a runtime exception, this is a bad example..

My mistake.

Tomas
 
T

Tomas Mikula

It is an exception handler.

But it is converting the exception that the designer of the API
being called consider a real possibility to an exception that should
never happen by the designer of the calling code.

The designer of the API may as well state that the declared exception
will only be thrown under certain circumstances. If I avoided these
circumstances, then the exception won't be thrown. I will provide an
example:

class WriterEncoder {
public WriterEncoder(Writer w);

/** @throws IOException if and only if the write() methods of
underlying Writer throw an exception. */
public void writeEncoded(MyClass obj) throws IOException;
}

Now if I construct the WriterEncoder with StringWriter which does not
throw IOException on write, I can be sure that
WriterEncoder.writeEncoded() won't throw IOException either.

That is a pretty serious decision. It makes sense to me that it
requires some rather explicit coding.

It *is* a serious decision and the outcome of that decision could be
using the @safe construct.
We need to decide whether we want to design Java after
making it easy for college students in the first months
of programming or whether we want to design a language
for real usage.

The main idea of the proposed construct is not making the code easier
to write (although that is another benefit), but making the code
easier to read (for everyone, not just college students).

Tomas
 
A

Arne Vajhøj

Tomas said:
The designer of the API may as well state that the declared exception
will only be thrown under certain circumstances. If I avoided these
circumstances, then the exception won't be thrown. I will provide an
example:

class WriterEncoder {
public WriterEncoder(Writer w);

/** @throws IOException if and only if the write() methods of
underlying Writer throw an exception. */
public void writeEncoded(MyClass obj) throws IOException;
}

Now if I construct the WriterEncoder with StringWriter which does not
throw IOException on write, I can be sure that
WriterEncoder.writeEncoded() won't throw IOException either.

Yes.

But it is very bad code.

The safe construct is relying on knowledge about implementation
of both the calling and the called code instead of just relying
on the exposed API's.
It *is* a serious decision and the outcome of that decision could be
using the @safe construct.


The main idea of the proposed construct is not making the code easier
to write (although that is another benefit), but making the code
easier to read (for everyone, not just college students).

For exception handling a catch block is very readable.

Well-known Java conecpt. Well-known in a lot of other OO
languages as well.

Arne
 
T

Tomas Mikula

Yes.

But it is very bad code.

The safe construct is relying on knowledge about implementation
of both the calling and the called code instead of just relying
on the exposed API's.

So what would be your solution? The task is (continuing on the above
example) to write a method for which it does not make sense to throw
an IOException. Yet it is advantageous to use WriterEncoder with
StringWriter from within this method. The best solution I can think of
is

try {
encoder.writeEncoded(obj);
} catch(IOException e) {
throw new AssertionError(e);
}

which is exactly what could be written more concisely with @safe.
For exception handling a catch block is very readable.

Well-known Java conecpt. Well-known in a lot of other OO
languages as well.

Yes, try-catch block alone is readable. But what about the method that
contains a couple of try-catch blocks?

Tomas
 
A

Arne Vajhøj

Tomas said:
So what would be your solution? The task is (continuing on the above
example) to write a method for which it does not make sense to throw
an IOException. Yet it is advantageous to use WriterEncoder with
StringWriter from within this method. The best solution I can think of
is

try {
encoder.writeEncoded(obj);
} catch(IOException e) {
throw new AssertionError(e);
}

which is exactly what could be written more concisely with @safe.

I would either catch the exception and do something to handle
the situation properly or let the exception bubble to where it
could be handled properly.

I would not tie my code to an implementation.
Yes, try-catch block alone is readable. But what about the method that
contains a couple of try-catch blocks?

Just as readable.

Especially if your other suggestion about multiple exceptions in
a single catch were added.

Arne
 
T

Tomas Mikula

Tomas Mikula wrote:

...> try {

...

I would not use AssertionError for this, for several reasons:

1. It has a defined meaning, "Thrown to indicate that an assertion has
failed.", that this usage does not match.

2. It breaks a key invariant for AssertionError. It is not thrown from
code that is run with assertions disabled.

3. Passing e to the AssertionError constructor forces the message to be
e.toString(). Is that the most useful message for explaining what is
going on?

Patricia

This is just a technical detail. AssertionError seemed most suitable
for me. But as AssertionError was introduced with assertions, some
other error could be introduced with the safe construct.

Tomas
 
L

Lew

It is an exception handler.

But it is converting the exception that the designer of the API
being called consider a real possibility to an exception that should
never happen by the designer of the calling code.

That is a pretty serious decision. It makes sense to me that it
requires some rather explicit coding.

Amen, brother!

I don't see the saving of six lines of typing to be worth the burial of this
serious a decision.

And tom, while the proposed @Safe (obviously it wouldn't be "@safe") "is" and
exception handler under the hood, it doesn't look like one. I espouse writing
explicit exception handlers for checked exceptions. The purpose of a checked
exception is to require explicit handling. To dodge that to save a few lines
of typing ("Ow! My poor fingers!") defeats that purpose, and as Arne points
out, moves the realm of expected exception to impossible error. A checked
exception is supposed to represent a recoverable situation, an error an
unrecoverable one. Why elevate the seriousness of the flaw?

I don't regard turning an exception into an error as "handling" it; it's
really just making it worse.

Instead of calling lazy programming "Java as it is" and a call to improve
coding practices putting one's head in the sand, if you become a proponent of
making Java (not "java") coding rigorous and disciplined, that's what looks
like a reasonable idea. Why promote laziness, poor design and whining?
 
L

Lew

Arne said:
I would either catch the exception and do something to handle
the situation properly or let the exception bubble to where it
could be handled properly.

I would not tie my code to an implementation.


Just as readable.

Especially if your other suggestion about multiple exceptions in
a single catch were added.

If you find try-catch blocks in Java unreadable, then you are not sufficiently
competent in Java, and I don't want you on my programming team. Go back and
learn the language instead of whining about it.
 
L

Lew

Tomas said:
Thank everyone for the opinions. I thought that @safe was something
everyone would like to have. But I see it didn't get much acceptance.
Still none of the arguments presented so far has convinced me that
it's a bad idea to have this in the language. But I would be happy
with more powerful annotations that would allow to change the code
being annotated at compile time.

@Safe (not "@safe") would be a marginally better idea if it converted a
checked exception into a runtime exception rather than an error.
 
T

Tomas Mikula

I would either catch the exception and do something to handle
the situation properly

From the beginning I'm talking about situations when throwing an error
is the most proper handling of the situation.
or let the exception bubble to where it
could be handled properly.

As I noted in the example, bubbling of the exception would be a
logical error - getting an IOException from a method that by
definition does not do any I/O.
I would not tie my code to an implementation.





Just as readable.

Especially if your other suggestion about multiple exceptions in
a single catch were added.

I disagree, but am not going to post another example to demonstrate
the readability improvement. Everyone can think for themselves.

Tomas
 
A

Arne Vajhøj

Ken said:
I would have to disagree here. This construct makes sense to me. Often
I know code won't throw an exception and I don't want to clutter it with
the try catch code.

I am very skeptical about the concept of "knowing" there will
not be any exception.

Code gets modified over decades and things change.
By using the safe annotation I'm asserting that the
code will not throw an exception. If it does, then the assertion is
false, and an AssertionError is reasonable.

The assertion is based on the current implementation not
the exposed API.
For point 2 above, I think
it reasonable that it be disabled when assertions are disabled, if this
is really an issue.

And what would happen then?

Nothing ? An unexpected checked exception ?
And point three is just an argument about what
exactly the message should be.

There is only one real argument against this as far as I'm concerned.
Java is very pedantic about some things. This can be a strength
depending on the application. If you really want a language with rules
that aren't so strict, why not look at groovy, or any of the other
languages out there that allow one to ignore exceptions when you don't
care about them.

I agree on that one.

There are plenty of that type of languages for the Java platform.
I wouldn't want my pacemaker software written in groovy. Java's
insistence on try catch blocks is one of the reasons it would be better
for this application.

Java would be a lot better than one of the dynamic typed languages.

But there are languages that would be even better than Java - like Ada.

Arne
 
T

Tomas Mikula

Amen, brother!

I don't see the saving of six lines of typing to be worth the burial of this
serious a decision.

Use of @Safe is the outcome of that decision. Noone is forced to use
it. If you think that it would encourage people to use it
inappropriately, then most probably these people would do worse things
(like empty catch blocks) without it.
And tom, while the proposed @Safe (obviously it wouldn't be "@safe") "is" and
exception handler under the hood, it doesn't look like one.  I espouse writing
explicit exception handlers for checked exceptions.  The purpose of a checked
exception is to require explicit handling.

Use of @Safe *is* explicit handling of exception. It's just a
different syntax.
 To dodge that to save a few lines
of typing ("Ow!  My poor fingers!") defeats that purpose,

As I already said, it's mainly about readability.
and as Arne points
out, moves the realm of expected exception to impossible error.  A checked
exception is supposed to represent a recoverable situation, an error an
unrecoverable one.  Why elevate the seriousness of the flaw?

Why not?? You do this every time you throw an exception or make an
assertion.

if(i<0)
throw new IllegalArgumentException("negative argument");

This is an elevation of invalid argument into a runtime exception.
I don't regard turning an exception into an error as "handling" it; it's
really just making it worse.

You are generalizing too much. In some cases it is a perfectly
suitable handling of an exception.

Tomas
 

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,770
Messages
2,569,584
Members
45,076
Latest member
OrderKetoBeez

Latest Threads

Top