why does catching errors that aren't thrown give syntax errors?

A

Arne Vajhøj

Lew said:
I just got bitten by a Java 6 change that broke existing code.

We have a bunch of things that rely on a library that has classes that
implement java.sql.Statement.
<http://java.sun.com/javase/6/docs/api/java/sql/Statement.html>

The library is compliant with Java 5. We compile it from source. The
interface has methods that were added in Java 6, so the code doesn't
compile under Java 6.

It is not quite the same problem.

But it is unfortunately a real problem.

It will happen when interfaces get stuff added.

I guess the official solution is that a JDBC n.m compliant
JDBC driver must be compiled with a Java version at that
JDBC version and just run on the newest Java version.

But that is highly problematic in real world development
environments.

The alternative would be pretty ugly though:
public interface Statement40 extends Statement30
public interface Statement30 extends Statement20
public interface Statement20 extends Statement

Arne
 
A

Arne Vajhøj

Bent said:
What C ought to have done from the very beginning is a different
debate.

And a lot of people would have suggestions that would effectively
have made it a different language.

Arne
 
A

Arne Vajh¸j

blue said:
I consider that kind of fiddly stuff to be an antipattern. #if(DEBUG) is
far, far better, much cleaner and more readable. Moreover, in the specific
case of Java it is not even applicable.

It does not matter.

Change to languages can not focus entirely on well written code.

It have to accommodate all valid code.

Arne
 
L

Lew

Steve said:
And I've got code where Integer.parseInt(s) is now throwing a

Is that 'Integer.parseInt( String s )'?
different exception.

What exception is that? The only checked exception that 'Integer.parseInt(
String s )' is documented to throw is 'NumberFormatException'.
The change took place between jdk 1.6.0_10
and jdk 1.6.0_12. My suspicion is that something that was broken
has now been fixed - and the code was written based on the broken
behavior.

According to

<http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#parseInt(java.lang.String)>
<http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Integer.html#parseInt(java.lang.String)>
<http://java.sun.com/j2se/1.3/docs/api/java/lang/Integer.html#parseInt(java.lang.String)>

that method has been throwing that exact same exception for quite some time.

My suspicion is that your suspicion is off base, and that the real problem was
a programmer error.
 
L

Lew

Arne said:
It is not quite the same problem.

But it is unfortunately a real problem.

It will happen when interfaces get stuff added.

I guess the official solution is that a JDBC n.m compliant
JDBC driver must be compiled with a Java version at that
JDBC version and just run on the newest Java version.

But that is highly problematic in real world development
environments.

The alternative would be pretty ugly though:
public interface Statement40 extends Statement30
public interface Statement30 extends Statement20
public interface Statement20 extends Statement

I'm going to recommend to the appropriate parties on my project that we use
the JARs for the code and not rebuild it from source.
 
B

blue indigo

You're welcome.

Wikimedia Commons has images and media related to the topic: sarcasm.
Look up sarcasm in Wiktionary, the free dictionary.
At Wikiversity you can learn more and teach others about sarcasm.
I did not comment on that, my comment was directed at the suggestion
that a retroactive change to accomplish this would be unproblematic.

Adding // comments was a not dissimilar change that actually did happen.
If you had made it clear from the start that your suggestion
/actually/ was "if everyone had written C code in some as yet to be
disclosed manner of my own invention then retroactively making this
change would not have been a problem" - we would not be having this
debate.

Yet to be disclosed? I thought I'd made it clear exactly how.
 
B

Bent C Dalager

Adding // comments was a not dissimilar change that actually did happen.

And notice how the line
int a = 2//**/1;
compiles fine with gcc -std=c89 but not with gcc -std=c++98.

Which, of course, proves my point yet again: this sort of change
requires language revision, it cannot just be blithely added with no
adverse consequences.
Yet to be disclosed? I thought I'd made it clear exactly how.

You had not, but you do appear to be working on it.

Cheers,
Bent D
 
A

Andreas Leitgeb

Lew said:
I'm going to recommend to the appropriate parties on my project that we use
the JARs for the code and not rebuild it from source.

But then you still cannot *run* it with an 1.6 JRE, unless I'm mistaken.
Or (of course) you could add implementations for the additional stuff.

As it seems from the Javadoc, 1.5 was the only version so far
that has not added to this interface (didn't show up in a "Since:").
Furthermore, enhancing of interfaces seems to be common practise in
the java.sql package (I looked randomly at a few other interfaces).
 
T

Tom Anderson

It certainly can -- an important part of the verifier is to statically
compute the stack depth and the types of the stack elements and local
variables for each opcode; this is done by a dataflow analysis which
basically retraces all possible paths which reach each opcode.

Any kind of JIT compiler must necessarily do something about dead
opcodes: since type information is not available for such opcodes, they
cannot be translated to machine instructions. The JIT compiler must
either reject the bytecode or explicitely skip dead opcodes. Only the
most basic intepretation model may avoid thinking about dead opcodes
and just let them sit where they are.

I don't believe any but the most naive JIT works by going through the
bytecodes in order and translating them one by one. Rather, they work by
building a representation from the bytecode, in something like single
static assignment form, and then compiling that. Building the
representation is done by pseudo-interpretation, walking all the possible
paths as you say above, and thus it never hits dead bytecodes.

However:
The JVM specification is quite unclear about the fine details of
bytecode verification, but it still states that the verifier must
compute the stack depth for each opcode; since such a depth is not
defined for unreachable opcodes, it cannot be computed, and thus,
arguably, the verifier must reject code which contains dead opcodes.

That's an excellent point. I suppose a JVM writer might choose not to do
this, because the stack layout at an unreachable bytecode is irrelevant -
for instance, they might fold stack depth computation into building a
compilable representation as i describe above, in which case unreachable
bytecodes will never have a stack depth, but also won't be added to the
set of things which need compiling - but by the letter of the law, they
should be rejected.

tom
 
B

blue indigo

And notice how the line
int a = 2//**/1;
compiles fine with gcc -std=c89 but not with gcc -std=c++98.

Which, of course, proves my point yet again: this sort of change
requires language revision, it cannot just be blithely added with no
adverse consequences.

I didn't say it could. I said it might nonetheless be a good choice, if
the adverse consequences are relatively minor and the benefits substantial.
You had not

Sure I had. The change is almost trivial: keep a count of how many /* have
been seen, decrease by one when */ is seen, toggle a boolean when " is
seen, and when the inside-quotes flag is set, don't count /* or */.

It might need further tweaking (character constants can contain multiple
characters I think, so single-quotes may also need to be tracked, for
instance). But it's nothing like as vague a notion as you seem to have
suggested I had.
 
T

Tom Anderson

It is not quite the same problem.

But it is unfortunately a real problem.

It will happen when interfaces get stuff added.

I guess the official solution is that a JDBC n.m compliant
JDBC driver must be compiled with a Java version at that
JDBC version and just run on the newest Java version.

But that is highly problematic in real world development
environments.

The alternative would be pretty ugly though:
public interface Statement40 extends Statement30
public interface Statement30 extends Statement20
public interface Statement20 extends Statement

You could imagine having language support for versioned interfaces, so
something like:

import java.sql.Statement;
public class LewsStatement implements Statement # 1.5 {
}

Or:

import java.sql.Statement # 1.5;
public class LewsStatement implements Statement {
}

Then elsewhere:

import java.sql.Statement # 1.4;
public class DatabaseProcessor {
public void Process(Statement stmt) ;
}

And as long as your class implements a version of Statement that's 1.4 or
later, it's a valid parameter. This is essentially syntactic sugar for
your 'ugly' code. It would require backward compatibility for subsequent
versions of an interface. I don't know for sure that this idea works -
we'd need a computer scientists to prove it, really.

Another option might be to have an abstract base class for implementing
the interface, which has concrete stubs for all the methods (which are
either no-op, delegate to other methods where possible, or throw
UnsupportedOperationException), so that as long as you extend that, you
conform to the interface even as it changes, because when the interface is
expanded, so is the base class. This isn't great, though, because the new
methods just have the base class implementations, and so will probably
fail in exciting and unhelpful ways at runtime. Plus, it constrains your
choice of base class.

tom
 
A

Arne Vajhøj

Lew said:
I'm going to recommend to the appropriate parties on my project that we
use the JARs for the code and not rebuild it from source.

Id it is external code that you can get as a binary dist (jar), then
that is of course fine.

My remark about problematic only applies when it is your
own code.

Arne
 
A

Arne Vajhøj

Andreas said:
But then you still cannot *run* it with an 1.6 JRE, unless I'm mistaken.

Sure he can.

He are not using any of the new methods.

If he were the code would not be compiling with the old Java version.

As it seems from the Javadoc, 1.5 was the only version so far
that has not added to this interface (didn't show up in a "Since:").
Furthermore, enhancing of interfaces seems to be common practise in
the java.sql package (I looked randomly at a few other interfaces).

It happen all the time.

But most people use binaries (jars) from JDBC drivers instead
of building themselves.

Arne
 
A

Arne Vajhøj

Tom said:
You could imagine having language support for versioned interfaces, so
something like:

import java.sql.Statement;
public class LewsStatement implements Statement # 1.5 {
}

Or:

import java.sql.Statement # 1.5;
public class LewsStatement implements Statement {
}

Then elsewhere:

import java.sql.Statement # 1.4;
public class DatabaseProcessor {
public void Process(Statement stmt) ;
}

And as long as your class implements a version of Statement that's 1.4
or later, it's a valid parameter. This is essentially syntactic sugar
for your 'ugly' code.

True.

But somehow I like a version feature in the language better than version
hacks.

The problem is well known in SOA context.

(I would still prefer JDBC version instead of Java version,
but that is besides the point)
It would require backward compatibility for
subsequent versions of an interface.

That is a benefit not a restriction !
I don't know for sure that this
idea works - we'd need a computer scientists to prove it, really.

:)

Arne
 
A

Arne Vajh¸j

blue said:
Sure I had. The change is almost trivial: keep a count of how many /* have
been seen, decrease by one when */ is seen, toggle a boolean when " is
seen, and when the inside-quotes flag is set, don't count /* or */.

It might need further tweaking (character constants can contain multiple
characters I think, so single-quotes may also need to be tracked, for
instance). But it's nothing like as vague a notion as you seem to have
suggested I had.

There are already posted examples where counting " and ' will not help.

Arne
 
M

Mike Schilling

Arne said:
There are already posted examples where counting " and ' will not
help.

It's already the case that // and /* inside a literal string don't
start comments (nor does */ inside a literal string end them.) It's
also the case that " or ' inside a comment don't delimit literal
strings. I'm not convinced that making /* ... */ nest makes the
situation significantly more complicated.
 
A

Arne Vajhøj

Mike said:
It's already the case that // and /* inside a literal string don't
start comments (nor does */ inside a literal string end them.) It's
also the case that " or ' inside a comment don't delimit literal
strings. I'm not convinced that making /* ... */ nest makes the
situation significantly more complicated.

True.

But there are other problems.

Arne
 
M

Mike Schilling

The fact that JDK 1.6 added methods to the interface
java.sql.Statement makes me curious about the general case of two
mismatched classes (or, in this case, a mismatched class and
interface.)

Say that at development time I have the class A:

class A implements Iface
{
public static void main(String[] args)
{
Iface i = new A();
i.doit();
}
public void doit()
{
}
}

interface Iface
{
void doit();
}

Clearly, this will compile and run just fine (mod any typos, anyway.)

Now, say that I modify Iface thus:

interface Iface
{
void doit();
int doit2();
}

Now I run the old A.class with the new Iface.class. We all know what
will happen: it will still run fine. When the JVM loads A, it won't
check that it implements all of the Iface methods, and since the only
Iface method called is one that A does implement, all is well. If
something tried to call Iface.doit2() on an A, there would be a
NoSuchMethod error thrown.

My question is whether this behavior is guaranteed and, if so, where
it's defined. Would a JVM be entitled to throw an error at

Iface i = new A();

on the grounds that A doesn't really implement Iface? More generally,
many odd things can happen when class definitions change between
compile time and run time. Is the JVM's behavior for all of them
well-defined?
 
A

Arne Vajhøj

Mike said:
The fact that JDK 1.6 added methods to the interface
java.sql.Statement makes me curious about the general case of two
mismatched classes (or, in this case, a mismatched class and
interface.)

Say that at development time I have the class A:

class A implements Iface
{
public static void main(String[] args)
{
Iface i = new A();
i.doit();
}
public void doit()
{
}
}

interface Iface
{
void doit();
}

Clearly, this will compile and run just fine (mod any typos, anyway.)

Now, say that I modify Iface thus:

interface Iface
{
void doit();
int doit2();
}

Now I run the old A.class with the new Iface.class. We all know what
will happen: it will still run fine. When the JVM loads A, it won't
check that it implements all of the Iface methods, and since the only
Iface method called is one that A does implement, all is well. If
something tried to call Iface.doit2() on an A, there would be a
NoSuchMethod error thrown.

My question is whether this behavior is guaranteed and, if so, where
it's defined. Would a JVM be entitled to throw an error at

Iface i = new A();

on the grounds that A doesn't really implement Iface? More generally,
many odd things can happen when class definitions change between
compile time and run time. Is the JVM's behavior for all of them
well-defined?

You will have to dig through JLS and JVM spec to get an
authoritative statement.

But given:

1) it would add huge overhead to verify all methods

2) it would break lot of code

3) http://java.sun.com/javase/6/docs/api/java/lang/NoSuchMethodError.html
wording

then I would not be particular worried.

Arne
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top