This page is no longer maintained — Please continue to the home page at www.scala-lang.org

At last, I finally realize that finally is not last

20 replies
Bill Venners
Joined: 2008-12-18,
User offline. Last seen 31 weeks 5 days ago.

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

Chris Twiner
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
Re: At last, I finally realize that finally is not last

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
>

anli
Joined: 2008-08-19,
User offline. Last seen 1 day 1 hour ago.
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
>

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 20 hours ago.
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
>>
>

anli
Joined: 2008-08-19,
User offline. Last seen 1 day 1 hour ago.
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...

Job Honig
Joined: 2009-08-17,
User offline. Last seen 42 years 45 weeks ago.
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

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 20 hours ago.
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.

Ricky Clarkson
Joined: 2008-12-19,
User offline. Last seen 3 years 2 weeks ago.
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?

Job Honig
Joined: 2009-08-17,
User offline. Last seen 42 years 45 weeks ago.
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 :-)

Johannes Rudolph
Joined: 2008-12-17,
User offline. Last seen 29 weeks 20 hours ago.
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.

Viktor Klang
Joined: 2008-12-17,
User offline. Last seen 1 year 27 weeks ago.
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
Florian Hars
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
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.

Vladimir Kirichenko
Joined: 2009-02-19,
User offline. Last seen 42 years 45 weeks ago.
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!

Bill Venners
Joined: 2008-12-18,
User offline. Last seen 31 weeks 5 days ago.
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
>

Iulian Dragos
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
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:
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
Joined: 2008-12-18,
User offline. Last seen 31 weeks 5 days ago.
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
>

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
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:
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
Joined: 2008-12-18,
User offline. Last seen 31 weeks 5 days ago.
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.
>

Raoul Duke
Joined: 2009-01-05,
User offline. Last seen 42 years 45 weeks ago.
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? :)

Iulian Dragos
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
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
Joshua.Suereth
Joined: 2008-09-02,
User offline. Last seen 32 weeks 5 days ago.
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:


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

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland