- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
At last, I finally realize that finally is not last
Fri, 2009-09-25, 06:00
Hi All,
I was quite stumped by a puzzler tonight, and I knew there must be
some explanation. I finally allowed myself to accept that Scala had to
be doing something that I was assuming it couldn't possibly be doing.
I tried a little test and it indeed had the surprising behavior. It
took me many hours to let myself doubt the compiler unfortunately. I
looked up in the Scala Language Spec and it seems vague on this point,
so here it is. Let me know if this is a bug or feature.
In Java, the following code doesn't print out GOT HERE:
class OE {
public static void main(String args[]) {
try {
System.out.println("hi");
}
catch (Exception e) {
System.out.println("GOT HERE");
}
finally {
throw new RuntimeException("ouch");
}
}
}
Run this and you get:
hi
Exception in thread "main" java.lang.RuntimeException: ouch
at OE.main(OE.java:11)
Try the equivalent, and pleasantly more concise Scala:
try {
println("hi")
}
catch {
case e => println("GOT HERE")
}
finally {
throw new RuntimeException("ouch")
}
And you get:
hi
GOT HERE
java.lang.RuntimeException: ouch
at Main$$anon$1.((virtual file):13)
at Main$.main((virtual file):4)
at Main.main((virtual file))
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
at scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(ScriptRunner.scala:381)
at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:414)
at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:413)
at scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
So in Scala, if a finally clause throws an exception that is covered
by the preceding catch clause, control hops *backwards* to the catch
clause and it executes *after* the finally clause has already
executed. Since the Spec was silent on this question, I thought I'd
ask first. Shall I file this as a bug, or is this a feature?
Thanks.
Bill
----
Bill Venners
Artima, Inc.
http://www.artima.com
Fri, 2009-09-25, 06:47
#2
Re: At last, I finally realize that finally is not last
On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
> which version? Its a crazy headache inducing bug.
For rather fresh trunk:
$ scala
Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK 64-Bit Server VM, Java 1.6.0_0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> try { println("try") } catch { case _ => println("catch") } finally { error("finally") }
try
catch
java.lang.RuntimeException: finally
at scala.Predef$.error(Predef.scala:96)
at .liftedTree1$1(:5)
at .(:5)
at .()
at RequestResult$.(:4)
at RequestResult$.()
at RequestResult$result()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>
> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners wrote:
> > Hi All,
> >
> > I was quite stumped by a puzzler tonight, and I knew there must be
> > some explanation. I finally allowed myself to accept that Scala had to
> > be doing something that I was assuming it couldn't possibly be doing.
> > I tried a little test and it indeed had the surprising behavior. It
> > took me many hours to let myself doubt the compiler unfortunately. I
> > looked up in the Scala Language Spec and it seems vague on this point,
> > so here it is. Let me know if this is a bug or feature.
> >
> > In Java, the following code doesn't print out GOT HERE:
> >
> > class OE {
> > public static void main(String args[]) {
> > try {
> > System.out.println("hi");
> > }
> > catch (Exception e) {
> > System.out.println("GOT HERE");
> > }
> > finally {
> > throw new RuntimeException("ouch");
> > }
> > }
> > }
> >
> > Run this and you get:
> >
> > hi
> > Exception in thread "main" java.lang.RuntimeException: ouch
> > at OE.main(OE.java:11)
> >
> > Try the equivalent, and pleasantly more concise Scala:
> >
> > try {
> > println("hi")
> > }
> > catch {
> > case e => println("GOT HERE")
> > }
> > finally {
> > throw new RuntimeException("ouch")
> > }
> >
> > And you get:
> >
> > hi
> > GOT HERE
> > java.lang.RuntimeException: ouch
> > at Main$$anon$1.((virtual file):13)
> > at Main$.main((virtual file):4)
> > at Main.main((virtual file))
> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> > at
> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
> >:39) at
> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
> > at
> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
> > at
> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
> >criptRunner.scala:381) at
> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
> >a:414) at
> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
> >a:413) at
> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
> > at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413) at
> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168) at
> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
> >
> > So in Scala, if a finally clause throws an exception that is covered
> > by the preceding catch clause, control hops *backwards* to the catch
> > clause and it executes *after* the finally clause has already
> > executed. Since the Spec was silent on this question, I thought I'd
> > ask first. Shall I file this as a bug, or is this a feature?
> >
> > Thanks.
> >
> > Bill
> > ----
> > Bill Venners
> > Artima, Inc.
> > http://www.artima.com
>
Fri, 2009-09-25, 07:27
#3
Re: At last, I finally realize that finally is not last
For full disclosure here's the difference in disassemblage between
Java and Scala. The finally block has been inserted three times. That
is as expected.
As you can see the difference is just in the Exception table:
While the Java version cuts the code range into pieces and applies an
exception handler only to the sections outside of the finally handler,
the Scala version doesn't.
Scala 2.7.4.final:
public void main(java.lang.String[]);
Code:
Stack=3, Locals=4, Args_size=2
0: getstatic #26; //Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #28; //String hi
5: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
8: new #34; //class java/lang/RuntimeException
11: dup
12: ldc #36; //String ouch
14: invokespecial #39; //Method
java/lang/RuntimeException."":(Ljava/lang/String;)V
17: athrow
18: astore_2
19: getstatic #26; //Field scala/Predef$.MODULE$:Lscala/Predef$;
22: ldc #41; //String GOT HERE
24: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
27: new #34; //class java/lang/RuntimeException
30: dup
31: ldc #36; //String ouch
33: invokespecial #39; //Method
java/lang/RuntimeException."":(Ljava/lang/String;)V
36: athrow
37: astore_3
38: new #34; //class java/lang/RuntimeException
41: dup
42: ldc #36; //String ouch
44: invokespecial #39; //Method
java/lang/RuntimeException."":(Ljava/lang/String;)V
47: athrow
Exception table:
from to target type
0 18 18 Class java/lang/Throwable
0 37 37 any
Java:
public static void main(java.lang.String[]);
Code:
Stack=3, Locals=3, Args_size=1
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String hi
5: invokevirtual #4; //Method
java/io/PrintStream.println:(Ljava/lang/String;)V
8: new #5; //class java/lang/RuntimeException
11: dup
12: ldc #6; //String ouch
14: invokespecial #7; //Method
java/lang/RuntimeException."":(Ljava/lang/String;)V
17: athrow
18: astore_1
19: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
22: ldc #9; //String GOT HERE
24: invokevirtual #4; //Method
java/io/PrintStream.println:(Ljava/lang/String;)V
27: new #5; //class java/lang/RuntimeException
30: dup
31: ldc #6; //String ouch
33: invokespecial #7; //Method
java/lang/RuntimeException."":(Ljava/lang/String;)V
36: athrow
37: astore_2
38: new #5; //class java/lang/RuntimeException
41: dup
42: ldc #6; //String ouch
44: invokespecial #7; //Method
java/lang/RuntimeException."":(Ljava/lang/String;)V
47: athrow
Exception table:
from to target type
0 8 18 Class java/lang/Exception
0 8 37 any
18 27 37 any
37 38 37 any
If you look even harder you can see that there are several bugs at
once with this. Adding some println tracing into the scala code:
try {
println("hi")
}
catch {
case e => println("GOT HERE")
}
finally {
println("in finally")
throw new RuntimeException("ouch")
}
and you will be even more surprised by the output (again scala 2.7.4.final):
hi
in finally
GOT HERE
in finally
in finally
java.lang.RuntimeException: ouch
at Test$.main(finally.scala:11)
at Test.main(finally.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Johannes
On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko wrote:
> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>> which version? Its a crazy headache inducing bug.
>
> For rather fresh trunk:
>
> $ scala
> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK 64-Bit Server VM, Java 1.6.0_0).
> Type in expressions to have them evaluated.
> Type :help for more information.
>
> scala> try { println("try") } catch { case _ => println("catch") } finally { error("finally") }
> try
> catch
> java.lang.RuntimeException: finally
> at scala.Predef$.error(Predef.scala:96)
> at .liftedTree1$1(:5)
> at .(:5)
> at .()
> at RequestResult$.(:4)
> at RequestResult$.()
> at RequestResult$result()
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>
>>
>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners wrote:
>> > Hi All,
>> >
>> > I was quite stumped by a puzzler tonight, and I knew there must be
>> > some explanation. I finally allowed myself to accept that Scala had to
>> > be doing something that I was assuming it couldn't possibly be doing.
>> > I tried a little test and it indeed had the surprising behavior. It
>> > took me many hours to let myself doubt the compiler unfortunately. I
>> > looked up in the Scala Language Spec and it seems vague on this point,
>> > so here it is. Let me know if this is a bug or feature.
>> >
>> > In Java, the following code doesn't print out GOT HERE:
>> >
>> > class OE {
>> > public static void main(String args[]) {
>> > try {
>> > System.out.println("hi");
>> > }
>> > catch (Exception e) {
>> > System.out.println("GOT HERE");
>> > }
>> > finally {
>> > throw new RuntimeException("ouch");
>> > }
>> > }
>> > }
>> >
>> > Run this and you get:
>> >
>> > hi
>> > Exception in thread "main" java.lang.RuntimeException: ouch
>> > at OE.main(OE.java:11)
>> >
>> > Try the equivalent, and pleasantly more concise Scala:
>> >
>> > try {
>> > println("hi")
>> > }
>> > catch {
>> > case e => println("GOT HERE")
>> > }
>> > finally {
>> > throw new RuntimeException("ouch")
>> > }
>> >
>> > And you get:
>> >
>> > hi
>> > GOT HERE
>> > java.lang.RuntimeException: ouch
>> > at Main$$anon$1.((virtual file):13)
>> > at Main$.main((virtual file):4)
>> > at Main.main((virtual file))
>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> > at
>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>> >:39) at
>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>> > at
>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> > at
>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>> >criptRunner.scala:381) at
>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >a:414) at
>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >a:413) at
>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>> > at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413) at
>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168) at
>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >
>> > So in Scala, if a finally clause throws an exception that is covered
>> > by the preceding catch clause, control hops *backwards* to the catch
>> > clause and it executes *after* the finally clause has already
>> > executed. Since the Spec was silent on this question, I thought I'd
>> > ask first. Shall I file this as a bug, or is this a feature?
>> >
>> > Thanks.
>> >
>> > Bill
>> > ----
>> > Bill Venners
>> > Artima, Inc.
>> > http://www.artima.com
>>
>
Fri, 2009-09-25, 07:47
#4
Re: At last, I finally realize that finally is not last
On Friday 25 September 2009 10:20:25 Johannes Rudolph wrote:
...
> and you will be even more surprised by the output (again scala
> 2.7.4.final):
>
> hi
> in finally
> GOT HERE
> in finally
> in finally
> java.lang.RuntimeException: ouch
> at Test$.main(finally.scala:11)
> at Test.main(finally.scala)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
> 57) at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorIm
> pl.java:43) at java.lang.reflect.Method.invoke(Method.java:616)
> at
> scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
> at
> scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49
> ) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
> at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
> at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>
> Johannes
Heh, and for this minute trunk:
scala> try { println("try") } catch { case e => println("catch " + e) } finally { println("finally"); error("error") }
try
finally
catch java.lang.RuntimeException: error
finally
finally
java.lang.RuntimeException: error
at scala.Predef$.error(Predef.scala:96)
at .liftedTree1$1(:5)
at .(:5)
at .()
at RequestResult$.(:4)
at RequestResult$.()
at RequestResult$result()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Nati...
Fri, 2009-09-25, 08:17
#5
Re: At last, I finally realize that finally is not last
Bill,
I would consider this a bug.
BTW: I consider it an argument for separating the "finally" clause from the
"try" construct and make it a new language construct that is useful on its
own. Something like:
with do finally .
Code would be a little less concise, but one gets much better control
over finalization of the construct in the "with" part. Only one variable
(restricted to be a val, maybe even?) allowed in that part, or otherwise
you don't know what to finalize in case of exceptions! This construct
could of course be used in combination with a try clause without a
finally...
with
val stream : new InputStream (...);
do
// read input
finally
stream.close ();
Note: both the "do" part and the "finally" part should be INSIDE the
scope of the entire "with" construct! The separation increases chances
that you'll get finalization right, both in the normal case and in the case
of exceptions.
Job H.
> I was quite stumped by a puzzler tonight, and I knew there must be
> some explanation. I finally allowed myself to accept that Scala had to
> be doing something that I was assuming it couldn't possibly be doing.
> I tried a little test and it indeed had the surprising behavior. It
> took me many hours to let myself doubt the compiler unfortunately. I
> looked up in the Scala Language Spec and it seems vague on this point,
> so here it is. Let me know if this is a bug or feature.
>
> In Java, the following code doesn't print out GOT HERE:
>
> class OE {
> public static void main(String args[]) {
> try {
> System.out.println("hi");
> }
> catch (Exception e) {
> System.out.println("GOT HERE");
> }
> finally {
> throw new RuntimeException("ouch");
> }
> }
> }
>
> Run this and you get:
>
> hi
> Exception in thread "main" java.lang.RuntimeException: ouch
> at OE.main(OE.java:11)
>
> Try the equivalent, and pleasantly more concise Scala:
>
> try {
> println("hi")
> }
> catch {
> case e => println("GOT HERE")
> }
> finally {
> throw new RuntimeException("ouch")
> }
>
> And you get:
>
> hi
> GOT HERE
> java.lang.RuntimeException: ouch
> at Main$$anon$1.((virtual file):13)
> at Main$.main((virtual file):4)
> at Main.main((virtual file))
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:3
>9) at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImp
>l.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
> at
> scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75) at
> scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
> at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
> at
> scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(Scr
>iptRunner.scala:381) at
> scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:
>414) at
> scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:
>413) at
> scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351) at
> scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413) at
> scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168) at
> scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>
> So in Scala, if a finally clause throws an exception that is covered
> by the preceding catch clause, control hops *backwards* to the catch
> clause and it executes *after* the finally clause has already
> executed. Since the Spec was silent on this question, I thought I'd
> ask first. Shall I file this as a bug, or is this a feature?
>
> Thanks.
>
> Bill
> ----
> Bill Venners
> Artima, Inc.
> http://www.artima.com
Fri, 2009-09-25, 08:47
#6
Re: At last, I finally realize that finally is not last
On Fri, Sep 25, 2009 at 9:16 AM, Job Honig wrote:
> BTW: I consider it an argument for separating the "finally" clause from the
> "try" construct and make it a new language construct that is useful on its
> own. Something like:
>
> with do finally .
>
> Code would be a little less concise, but one gets much better control
> over finalization of the construct in the "with" part. Only one variable
> (restricted to be a val, maybe even?) allowed in that part, or otherwise
> you don't know what to finalize in case of exceptions! This construct
> could of course be used in combination with a try clause without a
> finally...
>
> with
> val stream : new InputStream (...);
> do
> // read input
> finally
> stream.close ();
>
> Note: both the "do" part and the "finally" part should be INSIDE the
> scope of the entire "with" construct! The separation increases chances
> that you'll get finalization right, both in the normal case and in the case
> of exceptions.
You can build it yourself if you need to:
def `with`[T](init: =>T):With[T] =
new With[T]{
def `do`[X](doFunc:T=>X):Do[T,X] =
new Do[T,X]{
def `finally`(f:T => Unit):X = {
val res = init
try{
doFunc(res)
}
finally{
f(res)
}
}
}
}
trait With[T]{
def `do`[X](f:T=>X):Do[T,X]
}
trait Do[T,X]{
def `finally`(f:T=>Unit):X
}
def test = {
val i:Int = `with` {new java.io.FileInputStream("test")} `do`
{stream => stream.read} `finally` {_.close}
i
}
It would be better to write a function like
def withFileStream[R](filename:String)(f:FileInputStream => X):X
instead of relying on manual resource handling.
Fri, 2009-09-25, 08:57
#7
Re: At last, I finally realize that finally is not last
> I would consider this a bug.
Me too.
> BTW: I consider it an argument for separating the "finally" clause from the
> "try" construct and make it a new language construct that is useful on its
> own.
You consider a bug in the compiler an argument for creating a new
language construct?
Fri, 2009-09-25, 09:07
#8
Re: At last, I finally realize that finally is not last
> You consider a bug in the compiler an argument for creating a new
> language construct?
Nope. It was just circumstantional evidence :-)
Fri, 2009-09-25, 09:17
#9
Re: At last, I finally realize that finally is not last
On Fri, Sep 25, 2009 at 9:45 AM, Ricky Clarkson
wrote:
>> I would consider this a bug.
>
> Me too.
I think we should regard and advertise it as a feature. Calling the
finally-block 3 times as often as in Java is in fact a 200%
improvement over Java and should be properly appreciated.
Fri, 2009-09-25, 10:27
#10
Re: At last, I finally realize that finally is not last
On Fri, Sep 25, 2009 at 10:07 AM, Johannes Rudolph <johannes [dot] rudolph [at] googlemail [dot] com> wrote:
On Fri, Sep 25, 2009 at 9:45 AM, Ricky Clarkson
<ricky [dot] clarkson [at] gmail [dot] com> wrote:
>> I would consider this a bug.
>
> Me too.
I think we should regard and advertise it as a feature. Calling the
finally-block 3 times as often as in Java is in fact a 200%
improvement over Java and should be properly appreciated.
It's common rhetoric: Say what you're gonna say, say it and say what you have said.
Because, how can you be sure if it's finally executed unless you make absolutely sure, by trying a couple of times more?
--
Johannes
-----------------------------------------------
Johannes Rudolph
http://virtual-void.net
--
Viktor Klang
Blog: klangism.blogspot.com
Twttr: viktorklang
Lift Committer - liftweb.com
AKKA Committer - akkasource.org
Cassidy - github.com/viktorklang/Cassidy.git
SoftPub founder: http://groups.google.com/group/softpub
Fri, 2009-09-25, 11:37
#11
Re: At last, I finally realize that finally is not last
Andrew Gaydenko schrieb:
> Heh, and for this minute trunk:
The same for 2.7.4.final
- Florian.
Fri, 2009-09-25, 13:47
#12
Re: At last, I finally realize that finally is not last
Andrew Gaydenko wrote:
> Heh, and for this minute trunk:
2.7.5, 2.7.6 infected too:)
Uh, oh, it's everywhere!
Fri, 2009-09-25, 16:07
#13
Re: At last, I finally realize that finally is not last
Hi Johanees,
Funny I ran the same experiment this morning and noticed finally was
getting run three times. I am using 2.7.5 by the way. Clearly this is
a bug now. It's a finally clause, not a finallyfinallyfinally clause.
Bill
On Thu, Sep 24, 2009 at 11:20 PM, Johannes Rudolph
wrote:
> For full disclosure here's the difference in disassemblage between
> Java and Scala. The finally block has been inserted three times. That
> is as expected.
>
> As you can see the difference is just in the Exception table:
> While the Java version cuts the code range into pieces and applies an
> exception handler only to the sections outside of the finally handler,
> the Scala version doesn't.
>
> Scala 2.7.4.final:
>
> public void main(java.lang.String[]);
> Code:
> Stack=3, Locals=4, Args_size=2
> 0: getstatic #26; //Field scala/Predef$.MODULE$:Lscala/Predef$;
> 3: ldc #28; //String hi
> 5: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
> 8: new #34; //class java/lang/RuntimeException
> 11: dup
> 12: ldc #36; //String ouch
> 14: invokespecial #39; //Method
> java/lang/RuntimeException."":(Ljava/lang/String;)V
> 17: athrow
> 18: astore_2
> 19: getstatic #26; //Field scala/Predef$.MODULE$:Lscala/Predef$;
> 22: ldc #41; //String GOT HERE
> 24: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
> 27: new #34; //class java/lang/RuntimeException
> 30: dup
> 31: ldc #36; //String ouch
> 33: invokespecial #39; //Method
> java/lang/RuntimeException."":(Ljava/lang/String;)V
> 36: athrow
> 37: astore_3
> 38: new #34; //class java/lang/RuntimeException
> 41: dup
> 42: ldc #36; //String ouch
> 44: invokespecial #39; //Method
> java/lang/RuntimeException."":(Ljava/lang/String;)V
> 47: athrow
> Exception table:
> from to target type
> 0 18 18 Class java/lang/Throwable
>
> 0 37 37 any
>
> Java:
>
> public static void main(java.lang.String[]);
> Code:
> Stack=3, Locals=3, Args_size=1
> 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
> 3: ldc #3; //String hi
> 5: invokevirtual #4; //Method
> java/io/PrintStream.println:(Ljava/lang/String;)V
> 8: new #5; //class java/lang/RuntimeException
> 11: dup
> 12: ldc #6; //String ouch
> 14: invokespecial #7; //Method
> java/lang/RuntimeException."":(Ljava/lang/String;)V
> 17: athrow
> 18: astore_1
> 19: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
> 22: ldc #9; //String GOT HERE
> 24: invokevirtual #4; //Method
> java/io/PrintStream.println:(Ljava/lang/String;)V
> 27: new #5; //class java/lang/RuntimeException
> 30: dup
> 31: ldc #6; //String ouch
> 33: invokespecial #7; //Method
> java/lang/RuntimeException."":(Ljava/lang/String;)V
> 36: athrow
> 37: astore_2
> 38: new #5; //class java/lang/RuntimeException
> 41: dup
> 42: ldc #6; //String ouch
> 44: invokespecial #7; //Method
> java/lang/RuntimeException."":(Ljava/lang/String;)V
> 47: athrow
> Exception table:
> from to target type
> 0 8 18 Class java/lang/Exception
>
> 0 8 37 any
> 18 27 37 any
> 37 38 37 any
>
> If you look even harder you can see that there are several bugs at
> once with this. Adding some println tracing into the scala code:
>
> try {
> println("hi")
> }
> catch {
> case e => println("GOT HERE")
> }
> finally {
> println("in finally")
> throw new RuntimeException("ouch")
> }
>
> and you will be even more surprised by the output (again scala 2.7.4.final):
>
> hi
> in finally
> GOT HERE
> in finally
> in finally
> java.lang.RuntimeException: ouch
> at Test$.main(finally.scala:11)
> at Test.main(finally.scala)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> at java.lang.reflect.Method.invoke(Method.java:616)
> at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
> at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
> at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
> at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
> at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>
> Johannes
>
> On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko wrote:
>> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>>> which version? Its a crazy headache inducing bug.
>>
>> For rather fresh trunk:
>>
>> $ scala
>> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK 64-Bit Server VM, Java 1.6.0_0).
>> Type in expressions to have them evaluated.
>> Type :help for more information.
>>
>> scala> try { println("try") } catch { case _ => println("catch") } finally { error("finally") }
>> try
>> catch
>> java.lang.RuntimeException: finally
>> at scala.Predef$.error(Predef.scala:96)
>> at .liftedTree1$1(:5)
>> at .(:5)
>> at .()
>> at RequestResult$.(:4)
>> at RequestResult$.()
>> at RequestResult$result()
>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>>
>>>
>>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners wrote:
>>> > Hi All,
>>> >
>>> > I was quite stumped by a puzzler tonight, and I knew there must be
>>> > some explanation. I finally allowed myself to accept that Scala had to
>>> > be doing something that I was assuming it couldn't possibly be doing.
>>> > I tried a little test and it indeed had the surprising behavior. It
>>> > took me many hours to let myself doubt the compiler unfortunately. I
>>> > looked up in the Scala Language Spec and it seems vague on this point,
>>> > so here it is. Let me know if this is a bug or feature.
>>> >
>>> > In Java, the following code doesn't print out GOT HERE:
>>> >
>>> > class OE {
>>> > public static void main(String args[]) {
>>> > try {
>>> > System.out.println("hi");
>>> > }
>>> > catch (Exception e) {
>>> > System.out.println("GOT HERE");
>>> > }
>>> > finally {
>>> > throw new RuntimeException("ouch");
>>> > }
>>> > }
>>> > }
>>> >
>>> > Run this and you get:
>>> >
>>> > hi
>>> > Exception in thread "main" java.lang.RuntimeException: ouch
>>> > at OE.main(OE.java:11)
>>> >
>>> > Try the equivalent, and pleasantly more concise Scala:
>>> >
>>> > try {
>>> > println("hi")
>>> > }
>>> > catch {
>>> > case e => println("GOT HERE")
>>> > }
>>> > finally {
>>> > throw new RuntimeException("ouch")
>>> > }
>>> >
>>> > And you get:
>>> >
>>> > hi
>>> > GOT HERE
>>> > java.lang.RuntimeException: ouch
>>> > at Main$$anon$1.((virtual file):13)
>>> > at Main$.main((virtual file):4)
>>> > at Main.main((virtual file))
>>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>> > at
>>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>>> >:39) at
>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>>> > at
>>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>>> > at
>>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>>> >criptRunner.scala:381) at
>>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>>> >a:414) at
>>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>>> >a:413) at
>>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>>> > at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413) at
>>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168) at
>>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>>> >
>>> > So in Scala, if a finally clause throws an exception that is covered
>>> > by the preceding catch clause, control hops *backwards* to the catch
>>> > clause and it executes *after* the finally clause has already
>>> > executed. Since the Spec was silent on this question, I thought I'd
>>> > ask first. Shall I file this as a bug, or is this a feature?
>>> >
>>> > Thanks.
>>> >
>>> > Bill
>>> > ----
>>> > Bill Venners
>>> > Artima, Inc.
>>> > http://www.artima.com
>>>
>>
>
>
>
> --
> Johannes
>
> -----------------------------------------------
> Johannes Rudolph
> http://virtual-void.net
>
Fri, 2009-09-25, 16:37
#14
Re: At last, I finally realize that finally is not last
Yep, a pretty ugly one. Please file a ticket, we need to fix that for 2.8. BTW, thanks for the analysis, it's pretty clear where the error is.
thanks,
iulian
On Fri, Sep 25, 2009 at 4:59 PM, Bill Venners <bill [at] artima [dot] com> wrote:
--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais
thanks,
iulian
On Fri, Sep 25, 2009 at 4:59 PM, Bill Venners <bill [at] artima [dot] com> wrote:
Hi Johanees,
Funny I ran the same experiment this morning and noticed finally was
getting run three times. I am using 2.7.5 by the way. Clearly this is
a bug now. It's a finally clause, not a finallyfinallyfinally clause.
Bill
On Thu, Sep 24, 2009 at 11:20 PM, Johannes Rudolph
<johannes [dot] rudolph [at] googlemail [dot] com> wrote:
> For full disclosure here's the difference in disassemblage between
> Java and Scala. The finally block has been inserted three times. That
> is as expected.
>
> As you can see the difference is just in the Exception table:
> While the Java version cuts the code range into pieces and applies an
> exception handler only to the sections outside of the finally handler,
> the Scala version doesn't.
>
> Scala 2.7.4.final:
>
> public void main(java.lang.String[]);
> Code:
> Stack=3, Locals=4, Args_size=2
> 0: getstatic #26; //Field scala/Predef$.MODULE$:Lscala/Predef$;
> 3: ldc #28; //String hi
> 5: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
> 8: new #34; //class java/lang/RuntimeException
> 11: dup
> 12: ldc #36; //String ouch
> 14: invokespecial #39; //Method
> java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
> 17: athrow
> 18: astore_2
> 19: getstatic #26; //Field scala/Predef$.MODULE$:Lscala/Predef$;
> 22: ldc #41; //String GOT HERE
> 24: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
> 27: new #34; //class java/lang/RuntimeException
> 30: dup
> 31: ldc #36; //String ouch
> 33: invokespecial #39; //Method
> java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
> 36: athrow
> 37: astore_3
> 38: new #34; //class java/lang/RuntimeException
> 41: dup
> 42: ldc #36; //String ouch
> 44: invokespecial #39; //Method
> java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
> 47: athrow
> Exception table:
> from to target type
> 0 18 18 Class java/lang/Throwable
>
> 0 37 37 any
>
> Java:
>
> public static void main(java.lang.String[]);
> Code:
> Stack=3, Locals=3, Args_size=1
> 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
> 3: ldc #3; //String hi
> 5: invokevirtual #4; //Method
> java/io/PrintStream.println:(Ljava/lang/String;)V
> 8: new #5; //class java/lang/RuntimeException
> 11: dup
> 12: ldc #6; //String ouch
> 14: invokespecial #7; //Method
> java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
> 17: athrow
> 18: astore_1
> 19: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
> 22: ldc #9; //String GOT HERE
> 24: invokevirtual #4; //Method
> java/io/PrintStream.println:(Ljava/lang/String;)V
> 27: new #5; //class java/lang/RuntimeException
> 30: dup
> 31: ldc #6; //String ouch
> 33: invokespecial #7; //Method
> java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
> 36: athrow
> 37: astore_2
> 38: new #5; //class java/lang/RuntimeException
> 41: dup
> 42: ldc #6; //String ouch
> 44: invokespecial #7; //Method
> java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
> 47: athrow
> Exception table:
> from to target type
> 0 8 18 Class java/lang/Exception
>
> 0 8 37 any
> 18 27 37 any
> 37 38 37 any
>
> If you look even harder you can see that there are several bugs at
> once with this. Adding some println tracing into the scala code:
>
> try {
> println("hi")
> }
> catch {
> case e => println("GOT HERE")
> }
> finally {
> println("in finally")
> throw new RuntimeException("ouch")
> }
>
> and you will be even more surprised by the output (again scala 2.7.4.final):
>
> hi
> in finally
> GOT HERE
> in finally
> in finally
> java.lang.RuntimeException: ouch
> at Test$.main(finally.scala:11)
> at Test.main(finally.scala)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> at java.lang.reflect.Method.invoke(Method.java:616)
> at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
> at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
> at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
> at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
> at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>
> Johannes
>
> On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko <a [at] gaydenko [dot] com> wrote:
>> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>>> which version? Its a crazy headache inducing bug.
>>
>> For rather fresh trunk:
>>
>> $ scala
>> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK 64-Bit Server VM, Java 1.6.0_0).
>> Type in expressions to have them evaluated.
>> Type :help for more information.
>>
>> scala> try { println("try") } catch { case _ => println("catch") } finally { error("finally") }
>> try
>> catch
>> java.lang.RuntimeException: finally
>> at scala.Predef$.error(Predef.scala:96)
>> at .liftedTree1$1(<console>:5)
>> at .<init>(<console>:5)
>> at .<clinit>(<console>)
>> at RequestResult$.<init>(<console>:4)
>> at RequestResult$.<clinit>(<console>)
>> at RequestResult$result(<console>)
>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>>
>>>
>>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners <bill [at] artima [dot] com> wrote:
>>> > Hi All,
>>> >
>>> > I was quite stumped by a puzzler tonight, and I knew there must be
>>> > some explanation. I finally allowed myself to accept that Scala had to
>>> > be doing something that I was assuming it couldn't possibly be doing.
>>> > I tried a little test and it indeed had the surprising behavior. It
>>> > took me many hours to let myself doubt the compiler unfortunately. I
>>> > looked up in the Scala Language Spec and it seems vague on this point,
>>> > so here it is. Let me know if this is a bug or feature.
>>> >
>>> > In Java, the following code doesn't print out GOT HERE:
>>> >
>>> > class OE {
>>> > public static void main(String args[]) {
>>> > try {
>>> > System.out.println("hi");
>>> > }
>>> > catch (Exception e) {
>>> > System.out.println("GOT HERE");
>>> > }
>>> > finally {
>>> > throw new RuntimeException("ouch");
>>> > }
>>> > }
>>> > }
>>> >
>>> > Run this and you get:
>>> >
>>> > hi
>>> > Exception in thread "main" java.lang.RuntimeException: ouch
>>> > at OE.main(OE.java:11)
>>> >
>>> > Try the equivalent, and pleasantly more concise Scala:
>>> >
>>> > try {
>>> > println("hi")
>>> > }
>>> > catch {
>>> > case e => println("GOT HERE")
>>> > }
>>> > finally {
>>> > throw new RuntimeException("ouch")
>>> > }
>>> >
>>> > And you get:
>>> >
>>> > hi
>>> > GOT HERE
>>> > java.lang.RuntimeException: ouch
>>> > at Main$$anon$1.<init>((virtual file):13)
>>> > at Main$.main((virtual file):4)
>>> > at Main.main((virtual file))
>>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>> > at
>>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>>> >:39) at
>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>>> > at
>>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>>> > at
>>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>>> >criptRunner.scala:381) at
>>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>>> >a:414) at
>>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>>> >a:413) at
>>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>>> > at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413) at
>>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168) at
>>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>>> >
>>> > So in Scala, if a finally clause throws an exception that is covered
>>> > by the preceding catch clause, control hops *backwards* to the catch
>>> > clause and it executes *after* the finally clause has already
>>> > executed. Since the Spec was silent on this question, I thought I'd
>>> > ask first. Shall I file this as a bug, or is this a feature?
>>> >
>>> > Thanks.
>>> >
>>> > Bill
>>> > ----
>>> > Bill Venners
>>> > Artima, Inc.
>>> > http://www.artima.com
>>>
>>
>
>
>
> --
> Johannes
>
> -----------------------------------------------
> Johannes Rudolph
> http://virtual-void.net
>
--
Bill Venners
Artima, Inc.
http://www.artima.com
--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais
Fri, 2009-09-25, 17:07
#15
Re: At last, I finally realize that finally is not last
Hi Iulian,
Done:
https://lampsvn.epfl.ch/trac/scala/ticket/2392
Bill
On Fri, Sep 25, 2009 at 8:27 AM, Iulian Dragos wrote:
> Yep, a pretty ugly one. Please file a ticket, we need to fix that for 2.8.
> BTW, thanks for the analysis, it's pretty clear where the error is.
>
> thanks,
> iulian
>
> On Fri, Sep 25, 2009 at 4:59 PM, Bill Venners wrote:
>>
>> Hi Johanees,
>>
>> Funny I ran the same experiment this morning and noticed finally was
>> getting run three times. I am using 2.7.5 by the way. Clearly this is
>> a bug now. It's a finally clause, not a finallyfinallyfinally clause.
>>
>> Bill
>>
>>
>> On Thu, Sep 24, 2009 at 11:20 PM, Johannes Rudolph
>> wrote:
>> > For full disclosure here's the difference in disassemblage between
>> > Java and Scala. The finally block has been inserted three times. That
>> > is as expected.
>> >
>> > As you can see the difference is just in the Exception table:
>> > While the Java version cuts the code range into pieces and applies an
>> > exception handler only to the sections outside of the finally handler,
>> > the Scala version doesn't.
>> >
>> > Scala 2.7.4.final:
>> >
>> > public void main(java.lang.String[]);
>> > Code:
>> > Stack=3, Locals=4, Args_size=2
>> > 0: getstatic #26; //Field
>> > scala/Predef$.MODULE$:Lscala/Predef$;
>> > 3: ldc #28; //String hi
>> > 5: invokevirtual #32; //Method
>> > scala/Predef$.println:(Ljava/lang/Object;)V
>> > 8: new #34; //class java/lang/RuntimeException
>> > 11: dup
>> > 12: ldc #36; //String ouch
>> > 14: invokespecial #39; //Method
>> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> > 17: athrow
>> > 18: astore_2
>> > 19: getstatic #26; //Field
>> > scala/Predef$.MODULE$:Lscala/Predef$;
>> > 22: ldc #41; //String GOT HERE
>> > 24: invokevirtual #32; //Method
>> > scala/Predef$.println:(Ljava/lang/Object;)V
>> > 27: new #34; //class java/lang/RuntimeException
>> > 30: dup
>> > 31: ldc #36; //String ouch
>> > 33: invokespecial #39; //Method
>> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> > 36: athrow
>> > 37: astore_3
>> > 38: new #34; //class java/lang/RuntimeException
>> > 41: dup
>> > 42: ldc #36; //String ouch
>> > 44: invokespecial #39; //Method
>> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> > 47: athrow
>> > Exception table:
>> > from to target type
>> > 0 18 18 Class java/lang/Throwable
>> >
>> > 0 37 37 any
>> >
>> > Java:
>> >
>> > public static void main(java.lang.String[]);
>> > Code:
>> > Stack=3, Locals=3, Args_size=1
>> > 0: getstatic #2; //Field
>> > java/lang/System.out:Ljava/io/PrintStream;
>> > 3: ldc #3; //String hi
>> > 5: invokevirtual #4; //Method
>> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> > 8: new #5; //class java/lang/RuntimeException
>> > 11: dup
>> > 12: ldc #6; //String ouch
>> > 14: invokespecial #7; //Method
>> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> > 17: athrow
>> > 18: astore_1
>> > 19: getstatic #2; //Field
>> > java/lang/System.out:Ljava/io/PrintStream;
>> > 22: ldc #9; //String GOT HERE
>> > 24: invokevirtual #4; //Method
>> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> > 27: new #5; //class java/lang/RuntimeException
>> > 30: dup
>> > 31: ldc #6; //String ouch
>> > 33: invokespecial #7; //Method
>> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> > 36: athrow
>> > 37: astore_2
>> > 38: new #5; //class java/lang/RuntimeException
>> > 41: dup
>> > 42: ldc #6; //String ouch
>> > 44: invokespecial #7; //Method
>> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> > 47: athrow
>> > Exception table:
>> > from to target type
>> > 0 8 18 Class java/lang/Exception
>> >
>> > 0 8 37 any
>> > 18 27 37 any
>> > 37 38 37 any
>> >
>> > If you look even harder you can see that there are several bugs at
>> > once with this. Adding some println tracing into the scala code:
>> >
>> > try {
>> > println("hi")
>> > }
>> > catch {
>> > case e => println("GOT HERE")
>> > }
>> > finally {
>> > println("in finally")
>> > throw new RuntimeException("ouch")
>> > }
>> >
>> > and you will be even more surprised by the output (again scala
>> > 2.7.4.final):
>> >
>> > hi
>> > in finally
>> > GOT HERE
>> > in finally
>> > in finally
>> > java.lang.RuntimeException: ouch
>> > at Test$.main(finally.scala:11)
>> > at Test.main(finally.scala)
>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> > at
>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>> > at
>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>> > at java.lang.reflect.Method.invoke(Method.java:616)
>> > at
>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> > at
>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
>> > at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
>> > at
>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
>> > at
>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >
>> > Johannes
>> >
>> > On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko wrote:
>> >> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>> >>> which version? Its a crazy headache inducing bug.
>> >>
>> >> For rather fresh trunk:
>> >>
>> >> $ scala
>> >> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK 64-Bit
>> >> Server VM, Java 1.6.0_0).
>> >> Type in expressions to have them evaluated.
>> >> Type :help for more information.
>> >>
>> >> scala> try { println("try") } catch { case _ => println("catch") }
>> >> finally { error("finally") }
>> >> try
>> >> catch
>> >> java.lang.RuntimeException: finally
>> >> at scala.Predef$.error(Predef.scala:96)
>> >> at .liftedTree1$1(:5)
>> >> at .(:5)
>> >> at .()
>> >> at RequestResult$.(:4)
>> >> at RequestResult$.()
>> >> at RequestResult$result()
>> >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> >> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>> >>
>> >>>
>> >>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners wrote:
>> >>> > Hi All,
>> >>> >
>> >>> > I was quite stumped by a puzzler tonight, and I knew there must be
>> >>> > some explanation. I finally allowed myself to accept that Scala had
>> >>> > to
>> >>> > be doing something that I was assuming it couldn't possibly be
>> >>> > doing.
>> >>> > I tried a little test and it indeed had the surprising behavior. It
>> >>> > took me many hours to let myself doubt the compiler unfortunately. I
>> >>> > looked up in the Scala Language Spec and it seems vague on this
>> >>> > point,
>> >>> > so here it is. Let me know if this is a bug or feature.
>> >>> >
>> >>> > In Java, the following code doesn't print out GOT HERE:
>> >>> >
>> >>> > class OE {
>> >>> > public static void main(String args[]) {
>> >>> > try {
>> >>> > System.out.println("hi");
>> >>> > }
>> >>> > catch (Exception e) {
>> >>> > System.out.println("GOT HERE");
>> >>> > }
>> >>> > finally {
>> >>> > throw new RuntimeException("ouch");
>> >>> > }
>> >>> > }
>> >>> > }
>> >>> >
>> >>> > Run this and you get:
>> >>> >
>> >>> > hi
>> >>> > Exception in thread "main" java.lang.RuntimeException: ouch
>> >>> > at OE.main(OE.java:11)
>> >>> >
>> >>> > Try the equivalent, and pleasantly more concise Scala:
>> >>> >
>> >>> > try {
>> >>> > println("hi")
>> >>> > }
>> >>> > catch {
>> >>> > case e => println("GOT HERE")
>> >>> > }
>> >>> > finally {
>> >>> > throw new RuntimeException("ouch")
>> >>> > }
>> >>> >
>> >>> > And you get:
>> >>> >
>> >>> > hi
>> >>> > GOT HERE
>> >>> > java.lang.RuntimeException: ouch
>> >>> > at Main$$anon$1.((virtual file):13)
>> >>> > at Main$.main((virtual file):4)
>> >>> > at Main.main((virtual file))
>> >>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >>> > Method)
>> >>> > at
>> >>> >
>> >>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>> >>> >:39) at
>> >>> >
>> >>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>> >>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>> >>> > at
>> >>> >
>> >>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >>> > at
>> >>> >
>> >>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>> >>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>> >>> >criptRunner.scala:381) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >>> >a:414) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >>> >a:413) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>> >>> > at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413)
>> >>> > at
>> >>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168)
>> >>> > at
>> >>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >>> >
>> >>> > So in Scala, if a finally clause throws an exception that is covered
>> >>> > by the preceding catch clause, control hops *backwards* to the catch
>> >>> > clause and it executes *after* the finally clause has already
>> >>> > executed. Since the Spec was silent on this question, I thought I'd
>> >>> > ask first. Shall I file this as a bug, or is this a feature?
>> >>> >
>> >>> > Thanks.
>> >>> >
>> >>> > Bill
>> >>> > ----
>> >>> > Bill Venners
>> >>> > Artima, Inc.
>> >>> > http://www.artima.com
>> >>>
>> >>
>> >
>> >
>> >
>> > --
>> > Johannes
>> >
>> > -----------------------------------------------
>> > Johannes Rudolph
>> > http://virtual-void.net
>> >
>>
>>
>>
>> --
>> Bill Venners
>> Artima, Inc.
>> http://www.artima.com
>
>
>
> --
> « Je déteste la montagne, ça cache le paysage »
> Alphonse Allais
>
Fri, 2009-09-25, 18:07
#16
Re: At last, I finally realize that finally is not last
I have a consideration. I seem to recall from PinS (I'm guessing you have a copy of it ;) that the value returned normally and with the return clause in a try/catch/finally expression differs from Java. The way this is ping-ponging between finally and catch reminds me somehow of those differences.
Now, I don't know if there are tests for the return value of try/catch/finally, with and without "return". If not, I ask that these tests get written, to ensure that fixing this bug won't break that.
On Fri, Sep 25, 2009 at 1:03 PM, Bill Venners <bill [at] artima [dot] com> wrote:
--
Daniel C. Sobral
Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.
On Fri, Sep 25, 2009 at 1:03 PM, Bill Venners <bill [at] artima [dot] com> wrote:
Hi Iulian,
Done:
https://lampsvn.epfl.ch/trac/scala/ticket/2392
Bill
On Fri, Sep 25, 2009 at 8:27 AM, Iulian Dragos <jaguarul [at] gmail [dot] com> wrote:
> Yep, a pretty ugly one. Please file a ticket, we need to fix that for 2.8.
> BTW, thanks for the analysis, it's pretty clear where the error is.
>
> thanks,
> iulian
>
> On Fri, Sep 25, 2009 at 4:59 PM, Bill Venners <bill [at] artima [dot] com> wrote:
>>
>> Hi Johanees,
>>
>> Funny I ran the same experiment this morning and noticed finally was
>> getting run three times. I am using 2.7.5 by the way. Clearly this is
>> a bug now. It's a finally clause, not a finallyfinallyfinally clause.
>>
>> Bill
>>
>>
>> On Thu, Sep 24, 2009 at 11:20 PM, Johannes Rudolph
>> <johannes [dot] rudolph [at] googlemail [dot] com> wrote:
>> > For full disclosure here's the difference in disassemblage between
>> > Java and Scala. The finally block has been inserted three times. That
>> > is as expected.
>> >
>> > As you can see the difference is just in the Exception table:
>> > While the Java version cuts the code range into pieces and applies an
>> > exception handler only to the sections outside of the finally handler,
>> > the Scala version doesn't.
>> >
>> > Scala 2.7.4.final:
>> >
>> > public void main(java.lang.String[]);
>> > Code:
>> > Stack=3, Locals=4, Args_size=2
>> > 0: getstatic #26; //Field
>> > scala/Predef$.MODULE$:Lscala/Predef$;
>> > 3: ldc #28; //String hi
>> > 5: invokevirtual #32; //Method
>> > scala/Predef$.println:(Ljava/lang/Object;)V
>> > 8: new #34; //class java/lang/RuntimeException
>> > 11: dup
>> > 12: ldc #36; //String ouch
>> > 14: invokespecial #39; //Method
>> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> > 17: athrow
>> > 18: astore_2
>> > 19: getstatic #26; //Field
>> > scala/Predef$.MODULE$:Lscala/Predef$;
>> > 22: ldc #41; //String GOT HERE
>> > 24: invokevirtual #32; //Method
>> > scala/Predef$.println:(Ljava/lang/Object;)V
>> > 27: new #34; //class java/lang/RuntimeException
>> > 30: dup
>> > 31: ldc #36; //String ouch
>> > 33: invokespecial #39; //Method
>> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> > 36: athrow
>> > 37: astore_3
>> > 38: new #34; //class java/lang/RuntimeException
>> > 41: dup
>> > 42: ldc #36; //String ouch
>> > 44: invokespecial #39; //Method
>> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> > 47: athrow
>> > Exception table:
>> > from to target type
>> > 0 18 18 Class java/lang/Throwable
>> >
>> > 0 37 37 any
>> >
>> > Java:
>> >
>> > public static void main(java.lang.String[]);
>> > Code:
>> > Stack=3, Locals=3, Args_size=1
>> > 0: getstatic #2; //Field
>> > java/lang/System.out:Ljava/io/PrintStream;
>> > 3: ldc #3; //String hi
>> > 5: invokevirtual #4; //Method
>> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> > 8: new #5; //class java/lang/RuntimeException
>> > 11: dup
>> > 12: ldc #6; //String ouch
>> > 14: invokespecial #7; //Method
>> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> > 17: athrow
>> > 18: astore_1
>> > 19: getstatic #2; //Field
>> > java/lang/System.out:Ljava/io/PrintStream;
>> > 22: ldc #9; //String GOT HERE
>> > 24: invokevirtual #4; //Method
>> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> > 27: new #5; //class java/lang/RuntimeException
>> > 30: dup
>> > 31: ldc #6; //String ouch
>> > 33: invokespecial #7; //Method
>> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> > 36: athrow
>> > 37: astore_2
>> > 38: new #5; //class java/lang/RuntimeException
>> > 41: dup
>> > 42: ldc #6; //String ouch
>> > 44: invokespecial #7; //Method
>> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> > 47: athrow
>> > Exception table:
>> > from to target type
>> > 0 8 18 Class java/lang/Exception
>> >
>> > 0 8 37 any
>> > 18 27 37 any
>> > 37 38 37 any
>> >
>> > If you look even harder you can see that there are several bugs at
>> > once with this. Adding some println tracing into the scala code:
>> >
>> > try {
>> > println("hi")
>> > }
>> > catch {
>> > case e => println("GOT HERE")
>> > }
>> > finally {
>> > println("in finally")
>> > throw new RuntimeException("ouch")
>> > }
>> >
>> > and you will be even more surprised by the output (again scala
>> > 2.7.4.final):
>> >
>> > hi
>> > in finally
>> > GOT HERE
>> > in finally
>> > in finally
>> > java.lang.RuntimeException: ouch
>> > at Test$.main(finally.scala:11)
>> > at Test.main(finally.scala)
>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> > at
>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>> > at
>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>> > at java.lang.reflect.Method.invoke(Method.java:616)
>> > at
>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> > at
>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
>> > at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
>> > at
>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
>> > at
>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >
>> > Johannes
>> >
>> > On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko <a [at] gaydenko [dot] com> wrote:
>> >> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>> >>> which version? Its a crazy headache inducing bug.
>> >>
>> >> For rather fresh trunk:
>> >>
>> >> $ scala
>> >> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK 64-Bit
>> >> Server VM, Java 1.6.0_0).
>> >> Type in expressions to have them evaluated.
>> >> Type :help for more information.
>> >>
>> >> scala> try { println("try") } catch { case _ => println("catch") }
>> >> finally { error("finally") }
>> >> try
>> >> catch
>> >> java.lang.RuntimeException: finally
>> >> at scala.Predef$.error(Predef.scala:96)
>> >> at .liftedTree1$1(<console>:5)
>> >> at .<init>(<console>:5)
>> >> at .<clinit>(<console>)
>> >> at RequestResult$.<init>(<console>:4)
>> >> at RequestResult$.<clinit>(<console>)
>> >> at RequestResult$result(<console>)
>> >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> >> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>> >>
>> >>>
>> >>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners <bill [at] artima [dot] com> wrote:
>> >>> > Hi All,
>> >>> >
>> >>> > I was quite stumped by a puzzler tonight, and I knew there must be
>> >>> > some explanation. I finally allowed myself to accept that Scala had
>> >>> > to
>> >>> > be doing something that I was assuming it couldn't possibly be
>> >>> > doing.
>> >>> > I tried a little test and it indeed had the surprising behavior. It
>> >>> > took me many hours to let myself doubt the compiler unfortunately. I
>> >>> > looked up in the Scala Language Spec and it seems vague on this
>> >>> > point,
>> >>> > so here it is. Let me know if this is a bug or feature.
>> >>> >
>> >>> > In Java, the following code doesn't print out GOT HERE:
>> >>> >
>> >>> > class OE {
>> >>> > public static void main(String args[]) {
>> >>> > try {
>> >>> > System.out.println("hi");
>> >>> > }
>> >>> > catch (Exception e) {
>> >>> > System.out.println("GOT HERE");
>> >>> > }
>> >>> > finally {
>> >>> > throw new RuntimeException("ouch");
>> >>> > }
>> >>> > }
>> >>> > }
>> >>> >
>> >>> > Run this and you get:
>> >>> >
>> >>> > hi
>> >>> > Exception in thread "main" java.lang.RuntimeException: ouch
>> >>> > at OE.main(OE.java:11)
>> >>> >
>> >>> > Try the equivalent, and pleasantly more concise Scala:
>> >>> >
>> >>> > try {
>> >>> > println("hi")
>> >>> > }
>> >>> > catch {
>> >>> > case e => println("GOT HERE")
>> >>> > }
>> >>> > finally {
>> >>> > throw new RuntimeException("ouch")
>> >>> > }
>> >>> >
>> >>> > And you get:
>> >>> >
>> >>> > hi
>> >>> > GOT HERE
>> >>> > java.lang.RuntimeException: ouch
>> >>> > at Main$$anon$1.<init>((virtual file):13)
>> >>> > at Main$.main((virtual file):4)
>> >>> > at Main.main((virtual file))
>> >>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >>> > Method)
>> >>> > at
>> >>> >
>> >>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>> >>> >:39) at
>> >>> >
>> >>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>> >>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>> >>> > at
>> >>> >
>> >>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >>> > at
>> >>> >
>> >>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>> >>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>> >>> >criptRunner.scala:381) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >>> >a:414) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >>> >a:413) at
>> >>> >
>> >>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>> >>> > at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413)
>> >>> > at
>> >>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168)
>> >>> > at
>> >>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >>> >
>> >>> > So in Scala, if a finally clause throws an exception that is covered
>> >>> > by the preceding catch clause, control hops *backwards* to the catch
>> >>> > clause and it executes *after* the finally clause has already
>> >>> > executed. Since the Spec was silent on this question, I thought I'd
>> >>> > ask first. Shall I file this as a bug, or is this a feature?
>> >>> >
>> >>> > Thanks.
>> >>> >
>> >>> > Bill
>> >>> > ----
>> >>> > Bill Venners
>> >>> > Artima, Inc.
>> >>> > http://www.artima.com
>> >>>
>> >>
>> >
>> >
>> >
>> > --
>> > Johannes
>> >
>> > -----------------------------------------------
>> > Johannes Rudolph
>> > http://virtual-void.net
>> >
>>
>>
>>
>> --
>> Bill Venners
>> Artima, Inc.
>> http://www.artima.com
>
>
>
> --
> « Je déteste la montagne, ça cache le paysage »
> Alphonse Allais
>
--
Bill Venners
Artima, Inc.
http://www.artima.com
--
Daniel C. Sobral
Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.
Fri, 2009-09-25, 18:17
#17
Re: At last, I finally realize that finally is not last
Hi Daniel,
I second you on the tests. Also the spec was surprisingly vague. So
both clarification in the spec and tests would be good.
Iulian, can you point me in SVN where the tests are for the compiler?
Thanks.
Bill
On Fri, Sep 25, 2009 at 10:00 AM, Daniel Sobral wrote:
> I have a consideration. I seem to recall from PinS (I'm guessing you have a
> copy of it ;) that the value returned normally and with the return clause in
> a try/catch/finally expression differs from Java. The way this is
> ping-ponging between finally and catch reminds me somehow of those
> differences.
>
> Now, I don't know if there are tests for the return value of
> try/catch/finally, with and without "return". If not, I ask that these tests
> get written, to ensure that fixing this bug won't break that.
>
> On Fri, Sep 25, 2009 at 1:03 PM, Bill Venners wrote:
>>
>> Hi Iulian,
>>
>> Done:
>>
>> https://lampsvn.epfl.ch/trac/scala/ticket/2392
>>
>> Bill
>>
>> On Fri, Sep 25, 2009 at 8:27 AM, Iulian Dragos wrote:
>> > Yep, a pretty ugly one. Please file a ticket, we need to fix that for
>> > 2.8.
>> > BTW, thanks for the analysis, it's pretty clear where the error is.
>> >
>> > thanks,
>> > iulian
>> >
>> > On Fri, Sep 25, 2009 at 4:59 PM, Bill Venners wrote:
>> >>
>> >> Hi Johanees,
>> >>
>> >> Funny I ran the same experiment this morning and noticed finally was
>> >> getting run three times. I am using 2.7.5 by the way. Clearly this is
>> >> a bug now. It's a finally clause, not a finallyfinallyfinally clause.
>> >>
>> >> Bill
>> >>
>> >>
>> >> On Thu, Sep 24, 2009 at 11:20 PM, Johannes Rudolph
>> >> wrote:
>> >> > For full disclosure here's the difference in disassemblage between
>> >> > Java and Scala. The finally block has been inserted three times. That
>> >> > is as expected.
>> >> >
>> >> > As you can see the difference is just in the Exception table:
>> >> > While the Java version cuts the code range into pieces and applies an
>> >> > exception handler only to the sections outside of the finally
>> >> > handler,
>> >> > the Scala version doesn't.
>> >> >
>> >> > Scala 2.7.4.final:
>> >> >
>> >> > public void main(java.lang.String[]);
>> >> > Code:
>> >> > Stack=3, Locals=4, Args_size=2
>> >> > 0: getstatic #26; //Field
>> >> > scala/Predef$.MODULE$:Lscala/Predef$;
>> >> > 3: ldc #28; //String hi
>> >> > 5: invokevirtual #32; //Method
>> >> > scala/Predef$.println:(Ljava/lang/Object;)V
>> >> > 8: new #34; //class java/lang/RuntimeException
>> >> > 11: dup
>> >> > 12: ldc #36; //String ouch
>> >> > 14: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> >> > 17: athrow
>> >> > 18: astore_2
>> >> > 19: getstatic #26; //Field
>> >> > scala/Predef$.MODULE$:Lscala/Predef$;
>> >> > 22: ldc #41; //String GOT HERE
>> >> > 24: invokevirtual #32; //Method
>> >> > scala/Predef$.println:(Ljava/lang/Object;)V
>> >> > 27: new #34; //class java/lang/RuntimeException
>> >> > 30: dup
>> >> > 31: ldc #36; //String ouch
>> >> > 33: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> >> > 36: athrow
>> >> > 37: astore_3
>> >> > 38: new #34; //class java/lang/RuntimeException
>> >> > 41: dup
>> >> > 42: ldc #36; //String ouch
>> >> > 44: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> >> > 47: athrow
>> >> > Exception table:
>> >> > from to target type
>> >> > 0 18 18 Class java/lang/Throwable
>> >> >
>> >> > 0 37 37 any
>> >> >
>> >> > Java:
>> >> >
>> >> > public static void main(java.lang.String[]);
>> >> > Code:
>> >> > Stack=3, Locals=3, Args_size=1
>> >> > 0: getstatic #2; //Field
>> >> > java/lang/System.out:Ljava/io/PrintStream;
>> >> > 3: ldc #3; //String hi
>> >> > 5: invokevirtual #4; //Method
>> >> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> >> > 8: new #5; //class java/lang/RuntimeException
>> >> > 11: dup
>> >> > 12: ldc #6; //String ouch
>> >> > 14: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> >> > 17: athrow
>> >> > 18: astore_1
>> >> > 19: getstatic #2; //Field
>> >> > java/lang/System.out:Ljava/io/PrintStream;
>> >> > 22: ldc #9; //String GOT HERE
>> >> > 24: invokevirtual #4; //Method
>> >> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> >> > 27: new #5; //class java/lang/RuntimeException
>> >> > 30: dup
>> >> > 31: ldc #6; //String ouch
>> >> > 33: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> >> > 36: athrow
>> >> > 37: astore_2
>> >> > 38: new #5; //class java/lang/RuntimeException
>> >> > 41: dup
>> >> > 42: ldc #6; //String ouch
>> >> > 44: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."":(Ljava/lang/String;)V
>> >> > 47: athrow
>> >> > Exception table:
>> >> > from to target type
>> >> > 0 8 18 Class java/lang/Exception
>> >> >
>> >> > 0 8 37 any
>> >> > 18 27 37 any
>> >> > 37 38 37 any
>> >> >
>> >> > If you look even harder you can see that there are several bugs at
>> >> > once with this. Adding some println tracing into the scala code:
>> >> >
>> >> > try {
>> >> > println("hi")
>> >> > }
>> >> > catch {
>> >> > case e => println("GOT HERE")
>> >> > }
>> >> > finally {
>> >> > println("in finally")
>> >> > throw new RuntimeException("ouch")
>> >> > }
>> >> >
>> >> > and you will be even more surprised by the output (again scala
>> >> > 2.7.4.final):
>> >> >
>> >> > hi
>> >> > in finally
>> >> > GOT HERE
>> >> > in finally
>> >> > in finally
>> >> > java.lang.RuntimeException: ouch
>> >> > at Test$.main(finally.scala:11)
>> >> > at Test.main(finally.scala)
>> >> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> >> > at
>> >> >
>> >> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>> >> > at
>> >> >
>> >> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>> >> > at java.lang.reflect.Method.invoke(Method.java:616)
>> >> > at
>> >> >
>> >> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >> > at
>> >> >
>> >> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
>> >> > at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
>> >> > at
>> >> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
>> >> > at
>> >> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >> >
>> >> > Johannes
>> >> >
>> >> > On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko
>> >> > wrote:
>> >> >> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>> >> >>> which version? Its a crazy headache inducing bug.
>> >> >>
>> >> >> For rather fresh trunk:
>> >> >>
>> >> >> $ scala
>> >> >> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK
>> >> >> 64-Bit
>> >> >> Server VM, Java 1.6.0_0).
>> >> >> Type in expressions to have them evaluated.
>> >> >> Type :help for more information.
>> >> >>
>> >> >> scala> try { println("try") } catch { case _ => println("catch") }
>> >> >> finally { error("finally") }
>> >> >> try
>> >> >> catch
>> >> >> java.lang.RuntimeException: finally
>> >> >> at scala.Predef$.error(Predef.scala:96)
>> >> >> at .liftedTree1$1(:5)
>> >> >> at .(:5)
>> >> >> at .()
>> >> >> at RequestResult$.(:4)
>> >> >> at RequestResult$.()
>> >> >> at RequestResult$result()
>> >> >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >> >> Method)
>> >> >> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>> >> >>
>> >> >>>
>> >> >>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners
>> >> >>> wrote:
>> >> >>> > Hi All,
>> >> >>> >
>> >> >>> > I was quite stumped by a puzzler tonight, and I knew there must
>> >> >>> > be
>> >> >>> > some explanation. I finally allowed myself to accept that Scala
>> >> >>> > had
>> >> >>> > to
>> >> >>> > be doing something that I was assuming it couldn't possibly be
>> >> >>> > doing.
>> >> >>> > I tried a little test and it indeed had the surprising behavior.
>> >> >>> > It
>> >> >>> > took me many hours to let myself doubt the compiler
>> >> >>> > unfortunately. I
>> >> >>> > looked up in the Scala Language Spec and it seems vague on this
>> >> >>> > point,
>> >> >>> > so here it is. Let me know if this is a bug or feature.
>> >> >>> >
>> >> >>> > In Java, the following code doesn't print out GOT HERE:
>> >> >>> >
>> >> >>> > class OE {
>> >> >>> > public static void main(String args[]) {
>> >> >>> > try {
>> >> >>> > System.out.println("hi");
>> >> >>> > }
>> >> >>> > catch (Exception e) {
>> >> >>> > System.out.println("GOT HERE");
>> >> >>> > }
>> >> >>> > finally {
>> >> >>> > throw new RuntimeException("ouch");
>> >> >>> > }
>> >> >>> > }
>> >> >>> > }
>> >> >>> >
>> >> >>> > Run this and you get:
>> >> >>> >
>> >> >>> > hi
>> >> >>> > Exception in thread "main" java.lang.RuntimeException: ouch
>> >> >>> > at OE.main(OE.java:11)
>> >> >>> >
>> >> >>> > Try the equivalent, and pleasantly more concise Scala:
>> >> >>> >
>> >> >>> > try {
>> >> >>> > println("hi")
>> >> >>> > }
>> >> >>> > catch {
>> >> >>> > case e => println("GOT HERE")
>> >> >>> > }
>> >> >>> > finally {
>> >> >>> > throw new RuntimeException("ouch")
>> >> >>> > }
>> >> >>> >
>> >> >>> > And you get:
>> >> >>> >
>> >> >>> > hi
>> >> >>> > GOT HERE
>> >> >>> > java.lang.RuntimeException: ouch
>> >> >>> > at Main$$anon$1.((virtual file):13)
>> >> >>> > at Main$.main((virtual file):4)
>> >> >>> > at Main.main((virtual file))
>> >> >>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >> >>> > Method)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>> >> >>> >:39) at
>> >> >>> >
>> >> >>> >
>> >> >>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>> >> >>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>> >> >>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>> >> >>> >criptRunner.scala:381) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >> >>> >a:414) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >> >>> >a:413) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>> >> >>> > at
>> >> >>> > scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413)
>> >> >>> > at
>> >> >>> >
>> >> >>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168)
>> >> >>> > at
>> >> >>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >> >>> >
>> >> >>> > So in Scala, if a finally clause throws an exception that is
>> >> >>> > covered
>> >> >>> > by the preceding catch clause, control hops *backwards* to the
>> >> >>> > catch
>> >> >>> > clause and it executes *after* the finally clause has already
>> >> >>> > executed. Since the Spec was silent on this question, I thought
>> >> >>> > I'd
>> >> >>> > ask first. Shall I file this as a bug, or is this a feature?
>> >> >>> >
>> >> >>> > Thanks.
>> >> >>> >
>> >> >>> > Bill
>> >> >>> > ----
>> >> >>> > Bill Venners
>> >> >>> > Artima, Inc.
>> >> >>> > http://www.artima.com
>> >> >>>
>> >> >>
>> >> >
>> >> >
>> >> >
>> >> > --
>> >> > Johannes
>> >> >
>> >> > -----------------------------------------------
>> >> > Johannes Rudolph
>> >> > http://virtual-void.net
>> >> >
>> >>
>> >>
>> >>
>> >> --
>> >> Bill Venners
>> >> Artima, Inc.
>> >> http://www.artima.com
>> >
>> >
>> >
>> > --
>> > « Je déteste la montagne, ça cache le paysage »
>> > Alphonse Allais
>> >
>>
>>
>>
>> --
>> Bill Venners
>> Artima, Inc.
>> http://www.artima.com
>
>
>
> --
> Daniel C. Sobral
>
> Something I learned in academia: there are three kinds of academic reviews:
> review by name, review by reference and review by value.
>
Fri, 2009-09-25, 19:17
#18
Re: At last, I finally realize that finally is not last
> I second you on the tests. Also the spec was surprisingly vague. So
> both clarification in the spec and tests would be good.
> Iulian, can you point me in SVN where the tests are for the compiler?
word! there should be a contrib-tests-for-compiler package everybody
can contribute to? :)
Fri, 2009-09-25, 19:37
#19
Re: At last, I finally realize that finally is not last
On Fri, Sep 25, 2009 at 7:09 PM, Bill Venners <bill [at] artima [dot] com> wrote:
Hi Daniel,
I second you on the tests. Also the spec was surprisingly vague. So
both clarification in the spec and tests would be good.
Iulian, can you point me in SVN where the tests are for the compiler?
Of course, they reside under test/files/run:
http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/test/files/run
iulian
Thanks.
Bill
On Fri, Sep 25, 2009 at 10:00 AM, Daniel Sobral <dcsobral [at] gmail [dot] com> wrote:
> I have a consideration. I seem to recall from PinS (I'm guessing you have a
> copy of it ;) that the value returned normally and with the return clause in
> a try/catch/finally expression differs from Java. The way this is
> ping-ponging between finally and catch reminds me somehow of those
> differences.
>
> Now, I don't know if there are tests for the return value of
> try/catch/finally, with and without "return". If not, I ask that these tests
> get written, to ensure that fixing this bug won't break that.
>
> On Fri, Sep 25, 2009 at 1:03 PM, Bill Venners <bill [at] artima [dot] com> wrote:
>>
>> Hi Iulian,
>>
>> Done:
>>
>> https://lampsvn.epfl.ch/trac/scala/ticket/2392
>>
>> Bill
>>
>> On Fri, Sep 25, 2009 at 8:27 AM, Iulian Dragos <jaguarul [at] gmail [dot] com> wrote:
>> > Yep, a pretty ugly one. Please file a ticket, we need to fix that for
>> > 2.8.
>> > BTW, thanks for the analysis, it's pretty clear where the error is.
>> >
>> > thanks,
>> > iulian
>> >
>> > On Fri, Sep 25, 2009 at 4:59 PM, Bill Venners <bill [at] artima [dot] com> wrote:
>> >>
>> >> Hi Johanees,
>> >>
>> >> Funny I ran the same experiment this morning and noticed finally was
>> >> getting run three times. I am using 2.7.5 by the way. Clearly this is
>> >> a bug now. It's a finally clause, not a finallyfinallyfinally clause.
>> >>
>> >> Bill
>> >>
>> >>
>> >> On Thu, Sep 24, 2009 at 11:20 PM, Johannes Rudolph
>> >> <johannes [dot] rudolph [at] googlemail [dot] com> wrote:
>> >> > For full disclosure here's the difference in disassemblage between
>> >> > Java and Scala. The finally block has been inserted three times. That
>> >> > is as expected.
>> >> >
>> >> > As you can see the difference is just in the Exception table:
>> >> > While the Java version cuts the code range into pieces and applies an
>> >> > exception handler only to the sections outside of the finally
>> >> > handler,
>> >> > the Scala version doesn't.
>> >> >
>> >> > Scala 2.7.4.final:
>> >> >
>> >> > public void main(java.lang.String[]);
>> >> > Code:
>> >> > Stack=3, Locals=4, Args_size=2
>> >> > 0: getstatic #26; //Field
>> >> > scala/Predef$.MODULE$:Lscala/Predef$;
>> >> > 3: ldc #28; //String hi
>> >> > 5: invokevirtual #32; //Method
>> >> > scala/Predef$.println:(Ljava/lang/Object;)V
>> >> > 8: new #34; //class java/lang/RuntimeException
>> >> > 11: dup
>> >> > 12: ldc #36; //String ouch
>> >> > 14: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 17: athrow
>> >> > 18: astore_2
>> >> > 19: getstatic #26; //Field
>> >> > scala/Predef$.MODULE$:Lscala/Predef$;
>> >> > 22: ldc #41; //String GOT HERE
>> >> > 24: invokevirtual #32; //Method
>> >> > scala/Predef$.println:(Ljava/lang/Object;)V
>> >> > 27: new #34; //class java/lang/RuntimeException
>> >> > 30: dup
>> >> > 31: ldc #36; //String ouch
>> >> > 33: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 36: athrow
>> >> > 37: astore_3
>> >> > 38: new #34; //class java/lang/RuntimeException
>> >> > 41: dup
>> >> > 42: ldc #36; //String ouch
>> >> > 44: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 47: athrow
>> >> > Exception table:
>> >> > from to target type
>> >> > 0 18 18 Class java/lang/Throwable
>> >> >
>> >> > 0 37 37 any
>> >> >
>> >> > Java:
>> >> >
>> >> > public static void main(java.lang.String[]);
>> >> > Code:
>> >> > Stack=3, Locals=3, Args_size=1
>> >> > 0: getstatic #2; //Field
>> >> > java/lang/System.out:Ljava/io/PrintStream;
>> >> > 3: ldc #3; //String hi
>> >> > 5: invokevirtual #4; //Method
>> >> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> >> > 8: new #5; //class java/lang/RuntimeException
>> >> > 11: dup
>> >> > 12: ldc #6; //String ouch
>> >> > 14: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 17: athrow
>> >> > 18: astore_1
>> >> > 19: getstatic #2; //Field
>> >> > java/lang/System.out:Ljava/io/PrintStream;
>> >> > 22: ldc #9; //String GOT HERE
>> >> > 24: invokevirtual #4; //Method
>> >> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> >> > 27: new #5; //class java/lang/RuntimeException
>> >> > 30: dup
>> >> > 31: ldc #6; //String ouch
>> >> > 33: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 36: athrow
>> >> > 37: astore_2
>> >> > 38: new #5; //class java/lang/RuntimeException
>> >> > 41: dup
>> >> > 42: ldc #6; //String ouch
>> >> > 44: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 47: athrow
>> >> > Exception table:
>> >> > from to target type
>> >> > 0 8 18 Class java/lang/Exception
>> >> >
>> >> > 0 8 37 any
>> >> > 18 27 37 any
>> >> > 37 38 37 any
>> >> >
>> >> > If you look even harder you can see that there are several bugs at
>> >> > once with this. Adding some println tracing into the scala code:
>> >> >
>> >> > try {
>> >> > println("hi")
>> >> > }
>> >> > catch {
>> >> > case e => println("GOT HERE")
>> >> > }
>> >> > finally {
>> >> > println("in finally")
>> >> > throw new RuntimeException("ouch")
>> >> > }
>> >> >
>> >> > and you will be even more surprised by the output (again scala
>> >> > 2.7.4.final):
>> >> >
>> >> > hi
>> >> > in finally
>> >> > GOT HERE
>> >> > in finally
>> >> > in finally
>> >> > java.lang.RuntimeException: ouch
>> >> > at Test$.main(finally.scala:11)
>> >> > at Test.main(finally.scala)
>> >> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> >> > at
>> >> >
>> >> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>> >> > at
>> >> >
>> >> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>> >> > at java.lang.reflect.Method.invoke(Method.java:616)
>> >> > at
>> >> >
>> >> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >> > at
>> >> >
>> >> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
>> >> > at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
>> >> > at
>> >> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
>> >> > at
>> >> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >> >
>> >> > Johannes
>> >> >
>> >> > On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko <a [at] gaydenko [dot] com>
>> >> > wrote:
>> >> >> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>> >> >>> which version? Its a crazy headache inducing bug.
>> >> >>
>> >> >> For rather fresh trunk:
>> >> >>
>> >> >> $ scala
>> >> >> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK
>> >> >> 64-Bit
>> >> >> Server VM, Java 1.6.0_0).
>> >> >> Type in expressions to have them evaluated.
>> >> >> Type :help for more information.
>> >> >>
>> >> >> scala> try { println("try") } catch { case _ => println("catch") }
>> >> >> finally { error("finally") }
>> >> >> try
>> >> >> catch
>> >> >> java.lang.RuntimeException: finally
>> >> >> at scala.Predef$.error(Predef.scala:96)
>> >> >> at .liftedTree1$1(<console>:5)
>> >> >> at .<init>(<console>:5)
>> >> >> at .<clinit>(<console>)
>> >> >> at RequestResult$.<init>(<console>:4)
>> >> >> at RequestResult$.<clinit>(<console>)
>> >> >> at RequestResult$result(<console>)
>> >> >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >> >> Method)
>> >> >> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>> >> >>
>> >> >>>
>> >> >>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners <bill [at] artima [dot] com>
>> >> >>> wrote:
>> >> >>> > Hi All,
>> >> >>> >
>> >> >>> > I was quite stumped by a puzzler tonight, and I knew there must
>> >> >>> > be
>> >> >>> > some explanation. I finally allowed myself to accept that Scala
>> >> >>> > had
>> >> >>> > to
>> >> >>> > be doing something that I was assuming it couldn't possibly be
>> >> >>> > doing.
>> >> >>> > I tried a little test and it indeed had the surprising behavior.
>> >> >>> > It
>> >> >>> > took me many hours to let myself doubt the compiler
>> >> >>> > unfortunately. I
>> >> >>> > looked up in the Scala Language Spec and it seems vague on this
>> >> >>> > point,
>> >> >>> > so here it is. Let me know if this is a bug or feature.
>> >> >>> >
>> >> >>> > In Java, the following code doesn't print out GOT HERE:
>> >> >>> >
>> >> >>> > class OE {
>> >> >>> > public static void main(String args[]) {
>> >> >>> > try {
>> >> >>> > System.out.println("hi");
>> >> >>> > }
>> >> >>> > catch (Exception e) {
>> >> >>> > System.out.println("GOT HERE");
>> >> >>> > }
>> >> >>> > finally {
>> >> >>> > throw new RuntimeException("ouch");
>> >> >>> > }
>> >> >>> > }
>> >> >>> > }
>> >> >>> >
>> >> >>> > Run this and you get:
>> >> >>> >
>> >> >>> > hi
>> >> >>> > Exception in thread "main" java.lang.RuntimeException: ouch
>> >> >>> > at OE.main(OE.java:11)
>> >> >>> >
>> >> >>> > Try the equivalent, and pleasantly more concise Scala:
>> >> >>> >
>> >> >>> > try {
>> >> >>> > println("hi")
>> >> >>> > }
>> >> >>> > catch {
>> >> >>> > case e => println("GOT HERE")
>> >> >>> > }
>> >> >>> > finally {
>> >> >>> > throw new RuntimeException("ouch")
>> >> >>> > }
>> >> >>> >
>> >> >>> > And you get:
>> >> >>> >
>> >> >>> > hi
>> >> >>> > GOT HERE
>> >> >>> > java.lang.RuntimeException: ouch
>> >> >>> > at Main$$anon$1.<init>((virtual file):13)
>> >> >>> > at Main$.main((virtual file):4)
>> >> >>> > at Main.main((virtual file))
>> >> >>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >> >>> > Method)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>> >> >>> >:39) at
>> >> >>> >
>> >> >>> >
>> >> >>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>> >> >>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>> >> >>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>> >> >>> >criptRunner.scala:381) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >> >>> >a:414) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >> >>> >a:413) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>> >> >>> > at
>> >> >>> > scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413)
>> >> >>> > at
>> >> >>> >
>> >> >>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168)
>> >> >>> > at
>> >> >>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >> >>> >
>> >> >>> > So in Scala, if a finally clause throws an exception that is
>> >> >>> > covered
>> >> >>> > by the preceding catch clause, control hops *backwards* to the
>> >> >>> > catch
>> >> >>> > clause and it executes *after* the finally clause has already
>> >> >>> > executed. Since the Spec was silent on this question, I thought
>> >> >>> > I'd
>> >> >>> > ask first. Shall I file this as a bug, or is this a feature?
>> >> >>> >
>> >> >>> > Thanks.
>> >> >>> >
>> >> >>> > Bill
>> >> >>> > ----
>> >> >>> > Bill Venners
>> >> >>> > Artima, Inc.
>> >> >>> > http://www.artima.com
>> >> >>>
>> >> >>
>> >> >
>> >> >
>> >> >
>> >> > --
>> >> > Johannes
>> >> >
>> >> > -----------------------------------------------
>> >> > Johannes Rudolph
>> >> > http://virtual-void.net
>> >> >
>> >>
>> >>
>> >>
>> >> --
>> >> Bill Venners
>> >> Artima, Inc.
>> >> http://www.artima.com
>> >
>> >
>> >
>> > --
>> > « Je déteste la montagne, ça cache le paysage »
>> > Alphonse Allais
>> >
>>
>>
>>
>> --
>> Bill Venners
>> Artima, Inc.
>> http://www.artima.com
>
>
>
> --
> Daniel C. Sobral
>
> Something I learned in academia: there are three kinds of academic reviews:
> review by name, review by reference and review by value.
>
--
Bill Venners
Artima, Inc.
http://www.artima.com
--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais
Sat, 2009-09-26, 02:07
#20
Re: At last, I finally realize that finally is not last
Any chance I could get this fixed in the 2.7.x branch? If someone points me in the right direction, I'm willing to write tests/fix myself. I have code in production that uses finally blocks and this could tank my system (I'll have to do more error testing).
- Josh
On Fri, Sep 25, 2009 at 2:32 PM, Iulian Dragos <jaguarul [at] gmail [dot] com> wrote:
- Josh
On Fri, Sep 25, 2009 at 2:32 PM, Iulian Dragos <jaguarul [at] gmail [dot] com> wrote:
On Fri, Sep 25, 2009 at 7:09 PM, Bill Venners <bill [at] artima [dot] com> wrote:Hi Daniel,
I second you on the tests. Also the spec was surprisingly vague. So
both clarification in the spec and tests would be good.
Iulian, can you point me in SVN where the tests are for the compiler?
Of course, they reside under test/files/run:
http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/test/files/run
iulian
Thanks.
Bill
On Fri, Sep 25, 2009 at 10:00 AM, Daniel Sobral <dcsobral [at] gmail [dot] com> wrote:
> I have a consideration. I seem to recall from PinS (I'm guessing you have a
> copy of it ;) that the value returned normally and with the return clause in
> a try/catch/finally expression differs from Java. The way this is
> ping-ponging between finally and catch reminds me somehow of those
> differences.
>
> Now, I don't know if there are tests for the return value of
> try/catch/finally, with and without "return". If not, I ask that these tests
> get written, to ensure that fixing this bug won't break that.
>
> On Fri, Sep 25, 2009 at 1:03 PM, Bill Venners <bill [at] artima [dot] com> wrote:
>>
>> Hi Iulian,
>>
>> Done:
>>
>> https://lampsvn.epfl.ch/trac/scala/ticket/2392
>>
>> Bill
>>
>> On Fri, Sep 25, 2009 at 8:27 AM, Iulian Dragos <jaguarul [at] gmail [dot] com> wrote:
>> > Yep, a pretty ugly one. Please file a ticket, we need to fix that for
>> > 2.8.
>> > BTW, thanks for the analysis, it's pretty clear where the error is.
>> >
>> > thanks,
>> > iulian
>> >
>> > On Fri, Sep 25, 2009 at 4:59 PM, Bill Venners <bill [at] artima [dot] com> wrote:
>> >>
>> >> Hi Johanees,
>> >>
>> >> Funny I ran the same experiment this morning and noticed finally was
>> >> getting run three times. I am using 2.7.5 by the way. Clearly this is
>> >> a bug now. It's a finally clause, not a finallyfinallyfinally clause.
>> >>
>> >> Bill
>> >>
>> >>
>> >> On Thu, Sep 24, 2009 at 11:20 PM, Johannes Rudolph
>> >> <johannes [dot] rudolph [at] googlemail [dot] com> wrote:
>> >> > For full disclosure here's the difference in disassemblage between
>> >> > Java and Scala. The finally block has been inserted three times. That
>> >> > is as expected.
>> >> >
>> >> > As you can see the difference is just in the Exception table:
>> >> > While the Java version cuts the code range into pieces and applies an
>> >> > exception handler only to the sections outside of the finally
>> >> > handler,
>> >> > the Scala version doesn't.
>> >> >
>> >> > Scala 2.7.4.final:
>> >> >
>> >> > public void main(java.lang.String[]);
>> >> > Code:
>> >> > Stack=3, Locals=4, Args_size=2
>> >> > 0: getstatic #26; //Field
>> >> > scala/Predef$.MODULE$:Lscala/Predef$;
>> >> > 3: ldc #28; //String hi
>> >> > 5: invokevirtual #32; //Method
>> >> > scala/Predef$.println:(Ljava/lang/Object;)V
>> >> > 8: new #34; //class java/lang/RuntimeException
>> >> > 11: dup
>> >> > 12: ldc #36; //String ouch
>> >> > 14: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 17: athrow
>> >> > 18: astore_2
>> >> > 19: getstatic #26; //Field
>> >> > scala/Predef$.MODULE$:Lscala/Predef$;
>> >> > 22: ldc #41; //String GOT HERE
>> >> > 24: invokevirtual #32; //Method
>> >> > scala/Predef$.println:(Ljava/lang/Object;)V
>> >> > 27: new #34; //class java/lang/RuntimeException
>> >> > 30: dup
>> >> > 31: ldc #36; //String ouch
>> >> > 33: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 36: athrow
>> >> > 37: astore_3
>> >> > 38: new #34; //class java/lang/RuntimeException
>> >> > 41: dup
>> >> > 42: ldc #36; //String ouch
>> >> > 44: invokespecial #39; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 47: athrow
>> >> > Exception table:
>> >> > from to target type
>> >> > 0 18 18 Class java/lang/Throwable
>> >> >
>> >> > 0 37 37 any
>> >> >
>> >> > Java:
>> >> >
>> >> > public static void main(java.lang.String[]);
>> >> > Code:
>> >> > Stack=3, Locals=3, Args_size=1
>> >> > 0: getstatic #2; //Field
>> >> > java/lang/System.out:Ljava/io/PrintStream;
>> >> > 3: ldc #3; //String hi
>> >> > 5: invokevirtual #4; //Method
>> >> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> >> > 8: new #5; //class java/lang/RuntimeException
>> >> > 11: dup
>> >> > 12: ldc #6; //String ouch
>> >> > 14: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 17: athrow
>> >> > 18: astore_1
>> >> > 19: getstatic #2; //Field
>> >> > java/lang/System.out:Ljava/io/PrintStream;
>> >> > 22: ldc #9; //String GOT HERE
>> >> > 24: invokevirtual #4; //Method
>> >> > java/io/PrintStream.println:(Ljava/lang/String;)V
>> >> > 27: new #5; //class java/lang/RuntimeException
>> >> > 30: dup
>> >> > 31: ldc #6; //String ouch
>> >> > 33: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 36: athrow
>> >> > 37: astore_2
>> >> > 38: new #5; //class java/lang/RuntimeException
>> >> > 41: dup
>> >> > 42: ldc #6; //String ouch
>> >> > 44: invokespecial #7; //Method
>> >> > java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
>> >> > 47: athrow
>> >> > Exception table:
>> >> > from to target type
>> >> > 0 8 18 Class java/lang/Exception
>> >> >
>> >> > 0 8 37 any
>> >> > 18 27 37 any
>> >> > 37 38 37 any
>> >> >
>> >> > If you look even harder you can see that there are several bugs at
>> >> > once with this. Adding some println tracing into the scala code:
>> >> >
>> >> > try {
>> >> > println("hi")
>> >> > }
>> >> > catch {
>> >> > case e => println("GOT HERE")
>> >> > }
>> >> > finally {
>> >> > println("in finally")
>> >> > throw new RuntimeException("ouch")
>> >> > }
>> >> >
>> >> > and you will be even more surprised by the output (again scala
>> >> > 2.7.4.final):
>> >> >
>> >> > hi
>> >> > in finally
>> >> > GOT HERE
>> >> > in finally
>> >> > in finally
>> >> > java.lang.RuntimeException: ouch
>> >> > at Test$.main(finally.scala:11)
>> >> > at Test.main(finally.scala)
>> >> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>> >> > at
>> >> >
>> >> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>> >> > at
>> >> >
>> >> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>> >> > at java.lang.reflect.Method.invoke(Method.java:616)
>> >> > at
>> >> >
>> >> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >> > at
>> >> >
>> >> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
>> >> > at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
>> >> > at
>> >> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
>> >> > at
>> >> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >> >
>> >> > Johannes
>> >> >
>> >> > On Fri, Sep 25, 2009 at 7:43 AM, Andrew Gaydenko <a [at] gaydenko [dot] com>
>> >> > wrote:
>> >> >> On Friday 25 September 2009 09:06:31 Chris Twiner wrote:
>> >> >>> which version? Its a crazy headache inducing bug.
>> >> >>
>> >> >> For rather fresh trunk:
>> >> >>
>> >> >> $ scala
>> >> >> Welcome to Scala version 2.8.0.r18775-b20090924184428 (OpenJDK
>> >> >> 64-Bit
>> >> >> Server VM, Java 1.6.0_0).
>> >> >> Type in expressions to have them evaluated.
>> >> >> Type :help for more information.
>> >> >>
>> >> >> scala> try { println("try") } catch { case _ => println("catch") }
>> >> >> finally { error("finally") }
>> >> >> try
>> >> >> catch
>> >> >> java.lang.RuntimeException: finally
>> >> >> at scala.Predef$.error(Predef.scala:96)
>> >> >> at .liftedTree1$1(<console>:5)
>> >> >> at .<init>(<console>:5)
>> >> >> at .<clinit>(<console>)
>> >> >> at RequestResult$.<init>(<console>:4)
>> >> >> at RequestResult$.<clinit>(<console>)
>> >> >> at RequestResult$result(<console>)
>> >> >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >> >> Method)
>> >> >> at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
>> >> >>
>> >> >>>
>> >> >>> On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners <bill [at] artima [dot] com>
>> >> >>> wrote:
>> >> >>> > Hi All,
>> >> >>> >
>> >> >>> > I was quite stumped by a puzzler tonight, and I knew there must
>> >> >>> > be
>> >> >>> > some explanation. I finally allowed myself to accept that Scala
>> >> >>> > had
>> >> >>> > to
>> >> >>> > be doing something that I was assuming it couldn't possibly be
>> >> >>> > doing.
>> >> >>> > I tried a little test and it indeed had the surprising behavior.
>> >> >>> > It
>> >> >>> > took me many hours to let myself doubt the compiler
>> >> >>> > unfortunately. I
>> >> >>> > looked up in the Scala Language Spec and it seems vague on this
>> >> >>> > point,
>> >> >>> > so here it is. Let me know if this is a bug or feature.
>> >> >>> >
>> >> >>> > In Java, the following code doesn't print out GOT HERE:
>> >> >>> >
>> >> >>> > class OE {
>> >> >>> > public static void main(String args[]) {
>> >> >>> > try {
>> >> >>> > System.out.println("hi");
>> >> >>> > }
>> >> >>> > catch (Exception e) {
>> >> >>> > System.out.println("GOT HERE");
>> >> >>> > }
>> >> >>> > finally {
>> >> >>> > throw new RuntimeException("ouch");
>> >> >>> > }
>> >> >>> > }
>> >> >>> > }
>> >> >>> >
>> >> >>> > Run this and you get:
>> >> >>> >
>> >> >>> > hi
>> >> >>> > Exception in thread "main" java.lang.RuntimeException: ouch
>> >> >>> > at OE.main(OE.java:11)
>> >> >>> >
>> >> >>> > Try the equivalent, and pleasantly more concise Scala:
>> >> >>> >
>> >> >>> > try {
>> >> >>> > println("hi")
>> >> >>> > }
>> >> >>> > catch {
>> >> >>> > case e => println("GOT HERE")
>> >> >>> > }
>> >> >>> > finally {
>> >> >>> > throw new RuntimeException("ouch")
>> >> >>> > }
>> >> >>> >
>> >> >>> > And you get:
>> >> >>> >
>> >> >>> > hi
>> >> >>> > GOT HERE
>> >> >>> > java.lang.RuntimeException: ouch
>> >> >>> > at Main$$anon$1.<init>((virtual file):13)
>> >> >>> > at Main$.main((virtual file):4)
>> >> >>> > at Main.main((virtual file))
>> >> >>> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
>> >> >>> > Method)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java
>> >> >>> >:39) at
>> >> >>> >
>> >> >>> >
>> >> >>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI
>> >> >>> >mpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
>> >> >>> > at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:4
>> >> >>> >9) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(S
>> >> >>> >criptRunner.scala:381) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >> >>> >a:414) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scal
>> >> >>> >a:413) at
>> >> >>> >
>> >> >>> >
>> >> >>> > scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
>> >> >>> > at
>> >> >>> > scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413)
>> >> >>> > at
>> >> >>> >
>> >> >>> > scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168)
>> >> >>> > at
>> >> >>> > scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>> >> >>> >
>> >> >>> > So in Scala, if a finally clause throws an exception that is
>> >> >>> > covered
>> >> >>> > by the preceding catch clause, control hops *backwards* to the
>> >> >>> > catch
>> >> >>> > clause and it executes *after* the finally clause has already
>> >> >>> > executed. Since the Spec was silent on this question, I thought
>> >> >>> > I'd
>> >> >>> > ask first. Shall I file this as a bug, or is this a feature?
>> >> >>> >
>> >> >>> > Thanks.
>> >> >>> >
>> >> >>> > Bill
>> >> >>> > ----
>> >> >>> > Bill Venners
>> >> >>> > Artima, Inc.
>> >> >>> > http://www.artima.com
>> >> >>>
>> >> >>
>> >> >
>> >> >
>> >> >
>> >> > --
>> >> > Johannes
>> >> >
>> >> > -----------------------------------------------
>> >> > Johannes Rudolph
>> >> > http://virtual-void.net
>> >> >
>> >>
>> >>
>> >>
>> >> --
>> >> Bill Venners
>> >> Artima, Inc.
>> >> http://www.artima.com
>> >
>> >
>> >
>> > --
>> > « Je déteste la montagne, ça cache le paysage »
>> > Alphonse Allais
>> >
>>
>>
>>
>> --
>> Bill Venners
>> Artima, Inc.
>> http://www.artima.com
>
>
>
> --
> Daniel C. Sobral
>
> Something I learned in academia: there are three kinds of academic reviews:
> review by name, review by reference and review by value.
>
--
Bill Venners
Artima, Inc.
http://www.artima.com
--
« Je déteste la montagne, ça cache le paysage »
Alphonse Allais
which version? Its a crazy headache inducing bug.
On Fri, Sep 25, 2009 at 7:00 AM, Bill Venners wrote:
> Hi All,
>
> I was quite stumped by a puzzler tonight, and I knew there must be
> some explanation. I finally allowed myself to accept that Scala had to
> be doing something that I was assuming it couldn't possibly be doing.
> I tried a little test and it indeed had the surprising behavior. It
> took me many hours to let myself doubt the compiler unfortunately. I
> looked up in the Scala Language Spec and it seems vague on this point,
> so here it is. Let me know if this is a bug or feature.
>
> In Java, the following code doesn't print out GOT HERE:
>
> class OE {
> public static void main(String args[]) {
> try {
> System.out.println("hi");
> }
> catch (Exception e) {
> System.out.println("GOT HERE");
> }
> finally {
> throw new RuntimeException("ouch");
> }
> }
> }
>
> Run this and you get:
>
> hi
> Exception in thread "main" java.lang.RuntimeException: ouch
> at OE.main(OE.java:11)
>
> Try the equivalent, and pleasantly more concise Scala:
>
> try {
> println("hi")
> }
> catch {
> case e => println("GOT HERE")
> }
> finally {
> throw new RuntimeException("ouch")
> }
>
> And you get:
>
> hi
> GOT HERE
> java.lang.RuntimeException: ouch
> at Main$$anon$1.((virtual file):13)
> at Main$.main((virtual file):4)
> at Main.main((virtual file))
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:585)
> at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
> at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
> at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
> at scala.tools.nsc.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(ScriptRunner.scala:381)
> at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:414)
> at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:413)
> at scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:351)
> at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:413)
> at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:168)
> at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
>
> So in Scala, if a finally clause throws an exception that is covered
> by the preceding catch clause, control hops *backwards* to the catch
> clause and it executes *after* the finally clause has already
> executed. Since the Spec was silent on this question, I thought I'd
> ask first. Shall I file this as a bug, or is this a feature?
>
> Thanks.
>
> Bill
> ----
> Bill Venners
> Artima, Inc.
> http://www.artima.com
>