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

concurrency time bombs: exception swallowing

20 replies
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.

A recent commit to Manifest is as good an example as any -- here is the
surrounding context of r17585:

try {
[...]
} catch {
case _ => super.<:<(that)
}

I have spent the last couple days attempting to get up to speed on the
last ten years or so of concurrency developments. My conclusion so far
is that it's still ridiculously hard to get right. Unfortunately I
think at present scala is making it impossible to get right.

The scalac dist is loaded with try/catch clauses like the above which
indiscriminately swallow exceptions and even all throwables. I knew
this was unwise, but I didn't realize until this week how disastrous it
is for any code which utilizes more than one thread.

The problem (there may be many problems, but the one with which I have
become overly familiar of late) is that the entire framework for thread
interruption relies on throwing an InterruptedException which will be
observed where it needs to be. Swallowing this exception without
resetting the thread's interrupted status destroys this notification
utterly.

Here is an article about this:

http://www.ibm.com/developerworks/java/library/j-jtp05236.html

catch (InterruptedException swallowed) {
/* DON'T DO THIS - RESTORE THE INTERRUPTED STATUS INSTEAD */
}

I hope the size of this issue is clear. There is no way to work around
a library which swallows your exceptions, other than not using it.
There are at least a couple dozen spots in the compiler and library
which catch either "case e" or "case _" and that's just what I found
with a simple regexp; there are likely more which are better obscured.

I am willing to try to eradicate all of the existing ones, but I do not
think that is enough by itself because they will be reintroduced. The
scala catch syntax makes it too easy -- not that java makes it very
difficult, but the difference is that in java to catch everything you
have to type "catch (Throwable t)" and I think most developers know not
to do this. In scala you just type "case e" and it may never cross your
mind how far-reaching the effects of that may be.

One reason people take shortcuts here is that if you want to catch a few
different exceptions which don't have a common superclass, it's a
reasonably verbose PITA. Today it occurred to me that although the
native syntax doesn't make it as easy as it should, you can bundle
exceptions into an abstraction:

def catcher[T](cf: PartialFunction[Throwable, T], fin: => Unit) = {
def f(body: => Unit) =
try { body }
catch { case e if cf.isDefinedAt(e) => cf(e) }
finally { fin }
f _
}

I'm not sure if there's a reason why given a PF Throwable=>String I
can't say

try "abc" catch pf

but with something like the above we can come pretty close.

So! Here is what I propose:

1) I attempt to fix all existing instances of greedy swallowing.
2) The compiler issues a stern warning if you catch exceptions
without narrowing the type. (I'd prefer error.) You can still
catch everything by saying case t: Throwable => ... but is this
ever the right thing? At best it's infrequent.
3) If there are sensible groupings of exceptions that people find
themselves wanting a lot, we put some machinery in scala.control
or similar to make it easier.

Appreciate any feedback. Who knows, maybe I've misunderstood something
dramatic and this isn't as bad is it looks -- that'd actually be nice
because after two days of trying and failing to bulletproof what should
be a very simple concurrency scenario, to me it looks quite bad.

David Pollak
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: concurrency time bombs: exception swallowing
Paul,

Another part of the problem is a lot of the Exceptions raised by Scala libraries are rooted in java.lang.Error rather than java.lang.Exception.

If you're going to go through a fix the exception management in the compiler, I'd suggest fixing the Scala exception hierarchy so that Errors are thrown in dire circumstances (e.g., out of memory) rather than simply a program logic error (e.g., MatchError).

While the issues are not identical, they are rooted in the impedance mis-match between Java/JVM views of the exception hierarchy and the Scala view of the hierarchy.

Thanks,

David

On Tue, Apr 28, 2009 at 9:58 AM, Paul Phillips <paulp@improving.org> wrote:
A recent commit to Manifest is as good an example as any -- here is the
surrounding context of r17585:

 try {
   [...]
 } catch {
   case _ => super.<:<(that)
 }

I have spent the last couple days attempting to get up to speed on the
last ten years or so of concurrency developments.  My conclusion so far
is that it's still ridiculously hard to get right.  Unfortunately I
think at present scala is making it impossible to get right.

The scalac dist is loaded with try/catch clauses like the above which
indiscriminately swallow exceptions and even all throwables.  I knew
this was unwise, but I didn't realize until this week how disastrous it
is for any code which utilizes more than one thread.

The problem (there may be many problems, but the one with which I have
become overly familiar of late) is that the entire framework for thread
interruption relies on throwing an InterruptedException which will be
observed where it needs to be.  Swallowing this exception without
resetting the thread's interrupted status destroys this notification
utterly.

Here is an article about this:

 http://www.ibm.com/developerworks/java/library/j-jtp05236.html

 catch (InterruptedException swallowed) {
   /* DON'T DO THIS - RESTORE THE INTERRUPTED STATUS INSTEAD */
 }

I hope the size of this issue is clear.  There is no way to work around
a library which swallows your exceptions, other than not using it.
There are at least a couple dozen spots in the compiler and library
which catch either "case e" or "case _" and that's just what I found
with a simple regexp; there are likely more which are better obscured.

I am willing to try to eradicate all of the existing ones, but I do not
think that is enough by itself because they will be reintroduced.  The
scala catch syntax makes it too easy -- not that java makes it very
difficult, but the difference is that in java to catch everything you
have to type "catch (Throwable t)" and I think most developers know not
to do this.  In scala you just type "case e" and it may never cross your
mind how far-reaching the effects of that may be.

One reason people take shortcuts here is that if you want to catch a few
different exceptions which don't have a common superclass, it's a
reasonably verbose PITA.  Today it occurred to me that although the
native syntax doesn't make it as easy as it should, you can bundle
exceptions into an abstraction:

 def catcher[T](cf: PartialFunction[Throwable, T], fin: => Unit) = {
   def f(body: => Unit) =
     try { body }
     catch { case e if cf.isDefinedAt(e) => cf(e) }
     finally { fin }
   f _
 }

I'm not sure if there's a reason why given a PF Throwable=>String I
can't say

 try "abc" catch pf

but with something like the above we can come pretty close.

So! Here is what I propose:

 1) I attempt to fix all existing instances of greedy swallowing.
 2) The compiler issues a stern warning if you catch exceptions
   without narrowing the type.  (I'd prefer error.) You can still
   catch everything by saying case t: Throwable => ... but is this
   ever the right thing? At best it's infrequent.
 3) If there are sensible groupings of exceptions that people find
   themselves wanting a lot, we put some machinery in scala.control
   or similar to make it easier.

Appreciate any feedback.  Who knows, maybe I've misunderstood something
dramatic and this isn't as bad is it looks -- that'd actually be nice
because after two days of trying and failing to bulletproof what should
be a very simple concurrency scenario, to me it looks quite bad.

--
Paul Phillips      | We act as though comfort and luxury were the chief
Imperfectionist    | requirements of life, when all that we need to make us
Empiricist         | really happy is something to be enthusiastic about.
i pull his palp!   |     -- Charles Kingsley



--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp
milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 5:58 PM, Paul Phillips wrote:
> I hope the size of this issue is clear.  There is no way to work around
> a library which swallows your exceptions, other than not using it.

I disagree ...

It's the mechanics of interruption which is broken (because unfixably
unencapsulated) and which can't be relied on in any non-trivial
concurrent application. I would recommend against any library which
relies interrupts and hence on other components of an application not
interfering with them.

Cheers,

Miles

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 10:09:31AM -0700, David Pollak wrote:
> If you're going to go through a fix the exception management in the
> compiler, I'd suggest fixing the Scala exception hierarchy so that
> Errors are thrown in dire circumstances (e.g., out of memory) rather
> than simply a program logic error (e.g., MatchError).

MatchError calls itself Error, but it derives from RuntimeException.

I don't see any clear misuses of Error in trunk, but let me know if you
have specific examples I'm overlooking.

ijuma
Joined: 2008-08-20,
User offline. Last seen 22 weeks 2 days ago.
Re: concurrency time bombs: exception swallowing

Hi Paul,

On Tue, 2009-04-28 at 09:58 -0700, Paul Phillips wrote:
> One reason people take shortcuts here is that if you want to catch a few
> different exceptions which don't have a common superclass, it's a
> reasonably verbose PITA.

Not very pretty, but you can do:

try {
...
catch {
case e@(_: IOException | _: SocketException) => e.printStackTrace
}

Best,
Ismael

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 06:20:08PM +0100, Miles Sabin wrote:
> I disagree ...
>
> It's the mechanics of interruption which is broken (because unfixably
> unencapsulated) and which can't be relied on in any non-trivial
> concurrent application. I would recommend against any library which
> relies interrupts and hence on other components of an application not
> interfering with them.

I am finding the underlying logic as to when we must follow java's way
exactly and when we disregard it entirely difficult to grasp.

If it's not apparent what I mean by that, default encodings can't be
relied on in any non-trivial application either. Why is it important to
adhere to that, but we can casually destroy the only existing mechanism
(I think) for unblocking a blocked thread?

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 6:28 PM, Paul Phillips wrote:
> On Tue, Apr 28, 2009 at 06:20:08PM +0100, Miles Sabin wrote:
>> I disagree ...
>>
>> It's the mechanics of interruption which is broken (because unfixably
>> unencapsulated) and which can't be relied on in any non-trivial
>> concurrent application. I would recommend against any library which
>> relies interrupts and hence on other components of an application not
>> interfering with them.
>
> I am finding the underlying logic as to when we must follow java's way
> exactly and when we disregard it entirely difficult to grasp.
>
> If it's not apparent what I mean by that, default encodings can't be
> relied on in any non-trivial application either.  Why is it important to
> adhere to that, but we can casually destroy the only existing mechanism
> (I think) for unblocking a blocked thread?

This isn't a Scala/Java thing ...

I'd advise against libraries which rely on Java interrupts even in
Java-only applications. For instance, most Java or Scala libraries
which rely on interrupts can be broken, accidentally or maliciously,
by some other component enumerating threads and interrupting them.

It's far preferable to build first-class abstractions for dealing with
cancellable operations which don't rely on shared global interrupted
bits and which can be encapsulated sensibly.

Cheers,

Miles

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 5:58 PM, Paul Phillips wrote:
> Appreciate any feedback.  Who knows, maybe I've misunderstood something
> dramatic and this isn't as bad is it looks -- that'd actually be nice
> because after two days of trying and failing to bulletproof what should
> be a very simple concurrency scenario, to me it looks quite bad.

Actually on reflection, I think we're both getting side-tracked by the
interruption stuff ...

Exception swallowing is a problem other thing being equal (wrt
InterruptedException other things _aren't_ equal), and the exhibit
from Manifest is a pretty nasty example.

Cheers,

Miles

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 06:38:02PM +0100, Miles Sabin wrote:
> It's far preferable to build first-class abstractions for dealing with
> cancellable operations which don't rely on shared global interrupted
> bits and which can be encapsulated sensibly.

But doesn't this preference preclude using pretty much anything in
java.concurrent? Like I said I'm still trying to catch up on the state
of the concurrency art, but as far as I can tell if you use say
LinkedBlockingQueue and call queue.take, it will block until there is an
item in the queue or it is interrupted. There is no third option.
There is no second option either if we swallow exceptions.

What is the alternative which allows one to block interruptibly on lock
acquisition or I/O?

Is your viewpoint here commonly held? I just read most of "java
concurrency in practice" and I don't remember seeing a single word
arguing against the use of interrupt on this basis.

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 6:44 PM, Paul Phillips wrote:
> On Tue, Apr 28, 2009 at 06:38:02PM +0100, Miles Sabin wrote:
>> It's far preferable to build first-class abstractions for dealing with
>> cancellable operations which don't rely on shared global interrupted
>> bits and which can be encapsulated sensibly.
>
> But doesn't this preference preclude using pretty much anything in
> java.concurrent?

No, because the individual components of java.util.concurrent are very
careful to specify their behaviour when interrupted.

> Like I said I'm still trying to catch up on the state
> of the concurrency art, but as far as I can tell if you use say
> LinkedBlockingQueue and call queue.take, it will block until there is an
> item in the queue or it is interrupted. There is no third option.
> There is no second option either if we swallow exceptions.

The queue itself is behaving perfectly sensibly ... it's left in a
consistent state no matter where interruptions come from.

But a library which embeds an LinkedBlockingQueue and which depends on
interruption in this way? Chances are it's not going to behave
particularly well at all if some other application component
(accidentally or maliciously) interrupts one of it's threads.

If you need to cancel an operation which is waiting on one end of a
blocking queue the best approach is to send an explicit cancellation
token through that queue,

// Thread A blocking
val item = queue.take
if (item ne Cancel)
// Rinse and repeat
else
// Done now

Nb. that if the cancellation token is private to the component it
can't be sent accidentally or maliciously by any other component. This
is in contrast to an interrupt based model where cancellation can be
triggered by any component which can get a reference to the blocking
thread.

Assuming you've gone for an explicit cancellation mechanism like the
above (and exposed as much or as little of it as appropriate via a
well defined public API), then it would be perfectly sensible
(actually, pretty much required) to deliberately catch and ignore as
unintended or undesired any interrupts which come your way.

> What is the alternative which allows one to block interruptibly on lock
> acquisition or I/O?

Non-blocking I/O ;-)

That's actually not a joke: I/O interruption never worked
properly/portably ... NIO was in part motivated by the need for a
better solution to that problem.

Also take a look at java.util.concurrent.locks.Lock ... you'll notice
that the lock and tryLock methods do in fact ignore interrupts, and
that the interruptible behaviour is split out to separate
lockInterruptibly and overloaded tryLock methods.

Oh, and bear in mind that Java builtin locking (aka synchronization)
is not now nor has it ever been interruptible,

synchronized(foo) { // If blocked here you won't be unblocked by an interrupt
// stuff
}

> Is your viewpoint here commonly held? I just read most of "java
> concurrency in practice" and I don't remember seeing a single word
> arguing against the use of interrupt on this basis.

I've discussed this on and off with Doug Lea over the years. From
memory I think he was mainly sympathetic but thought I was taking a
slightly extreme position (but only slightly).

Cheers,

Miles

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

It sounds like we agree that the exception swallowing issue is
independent of the interruption issue, so hopefully that won't get lost
here. That said, I can't tell you how happy I am that you just talked
me into not relying on Thread.interrupt for anything. The poison object
had been my original approach but I had to deal with race conditions
having to do with the iterator hasNext/next disconnect. You made me
focus more on making that approach work right, which it does now, to my
lasting relief.

I still had to use interrupt because of the way the XML library is
structured, but now it amounts to an optimzation - if the interrupt were
to be swallowed the producer thread would keep merrily producing, but
the iterator interface would correctly terminate regardless.

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 8:16 PM, Paul Phillips wrote:
> I still had to use interrupt because of the way the XML library is
> structured, but now it amounts to an optimzation - if the interrupt were
> to be swallowed the producer thread would keep merrily producing, but
> the iterator interface would correctly terminate regardless.

Are you sure there isn't a resource revocation option available to
cancel the XML library's operation? Ie. close an InputStream out from
underneath it to trigger an IOException.

JCIP is a great book, but I'd still recommend Doug's earlier
Concurrent Programming in Java.

Cheers,

Miles

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 08:50:31PM +0100, Miles Sabin wrote:
> Are you sure there isn't a resource revocation option available to
> cancel the XML library's operation? Ie. close an InputStream out from
> underneath it to trigger an IOException.

From the XML parser's viewpoint it's operating on a scala.io.Source,
which does not expose the underlying stream. I could add a close method
to Source (and maybe should) which would be a no-op on sources from
Strings or whatever, but for the purposes of this parser I've been
trying to operate within the existing interfaces.

I suppose I could override nextch to check if it's been cancelled before
invoking the method in the superclass, but that's a lot of expense for
something that's only there as a safety valve.

And there are lots of changes that could be made to the XML libs, but
I'm too happy to have this thing done to go any deeper right now.

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 9:11 PM, Paul Phillips wrote:
> On Tue, Apr 28, 2009 at 08:50:31PM +0100, Miles Sabin wrote:
>> Are you sure there isn't a resource revocation option available to
>> cancel the XML library's operation? Ie. close an InputStream out from
>> underneath it to trigger an IOException.
>
> From the XML parser's viewpoint it's operating on a scala.io.Source,
> which does not expose the underlying stream.  I could add a close method
> to Source (and maybe should) which would be a no-op on sources from
> Strings or whatever, but for the purposes of this parser I've been
> trying to operate within the existing interfaces.

So what happens with infinite streams? Will there be something that
keeps reading from them regardless?

Cheers,

Miles

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 09:15:56PM +0100, Miles Sabin wrote:
> So what happens with infinite streams? Will there be something that
> keeps reading from them regardless?

The iterator proceeds until it finds an end of stream marker. I'm not
100% sure what you're asking, but if you're referring to the hopefully
degenerate case where the interrupt is lost and the underlying source
was infinite, then it'll still stop fairly soon because the queue size
is bounded.

You can inspect it directly if you like as I've now checked it in:

https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala...

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 9:33 PM, Paul Phillips wrote:
> On Tue, Apr 28, 2009 at 09:15:56PM +0100, Miles Sabin wrote:
>> So what happens with infinite streams? Will there be something that
>> keeps reading from them regardless?
>
> The iterator proceeds until it finds an end of stream marker.  I'm not
> 100% sure what you're asking, but if you're referring to the hopefully
> degenerate case where the interrupt is lost and the underlying source
> was infinite, then it'll still stop fairly soon because the queue size
> is bounded.
>
> You can inspect it directly if you like as I've now checked it in:
>
>  https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala/xml/pull/XMLEventReader.scala?rev=17591

Well, even if the interrupt isn't consumed, there's no guarantee that the

parserThread.interrupt()

will have any effect. Even where it does it's likely to be platform
dependent where the underlying stream is I/O based. That means that
each unsuccessfully cancelled parser will leak a queue-full's worth of
memory. Not so great ...

But heck, this is probably no worse that what was there before ... if
I was you I'd declare victory and move on to something more
interesting.

Cheers,

Miles

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 4 days ago.
Re: concurrency time bombs: exception swallowing

 2) The compiler issues a stern warning if you catch exceptions
   without narrowing the type.  (I'd prefer error.) You can still
   catch everything by saying case t: Throwable => ... but is this
   ever the right thing? At best it's infrequent.

Yes, please. I'd prefer error too.

--j

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: concurrency time bombs: exception swallowing

On Tue, Apr 28, 2009 at 01:56:04PM -0700, Jorge Ortiz wrote:
> Yes, please. I'd prefer error too.

Just as a little more grist for the mill, this is what the compiler told
me when I encouraged it to burble when it saw a default pattern in a
catch clause. These are only the pure defaults, not including any
additional "case e: Throwable" or "case e: Exception" which also exist.

Some of these do really interesting stuff - here is a favorite:

} catch {
case e => throw new java.lang.IndexOutOfBoundsException(blah blah)
}

ClassPath.scala, line 337
Code.scala, line 204
CodeWriter.scala, line 132
CodeWriter.scala, line 63
ComboBoxes.scala, line 63
Erasure.scala, line 1080
FastScalac.scala, line 109
Global.scala, line 184
IdeSupport.scala, line 202
IdeSupport.scala, line 310
IdeSupport.scala, line 35
IdeSupport.scala, line 39
Inliners.scala, line 375
Inliners.scala, line 75
InteractiveReader.scala, line 24
Interpreter.scala, line 794
JLineReader.scala, line 21
MainGenericRunner.scala, line 101
MainGenericRunner.scala, line 118
Manifest.scala, line 110
MarkupParsers.scala, line 101
MetaParser.scala, line 67
ModelFrames.scala, line 388
ModelToXML.scala, line 117
Relation.scala, line 43
Scalac.scala, line 684
Scaladoc.scala, line 629
ScriptRunner.scala, line 367
ScriptRunner.scala, line 419
ScriptRunner.scala, line 445
SyncVar.scala, line 63
Tests.scala, line 68
Tuple.scala, line 31
ZipArchive.scala, line 238
ops.scala, line 33

dubochet
Joined: 2008-06-30,
User offline. Last seen 1 year 36 weeks ago.
Re: concurrency time bombs: exception swallowing

I had a look at a few of the cases in your list. Some are somewhat
legitimate, in that they always re-throw the exception after printing
some debugging info (for example on line 333 of
scala.tools.nsc.util.ClassPath). Some are clearly signs of laziness
and are potentially problematic (for example on line 43 of
scala.dbc.result.Relation to give an example in my own code).

It would be good to review problematic cases in the compiler and
library. Paul, do you think you could encourage the compiler to burble
in non-default cases too (and maybe stay silent when the exception is
then thrown again), and post the resulting list.

>> Yes, please. I'd prefer error too.
>
> Just as a little more grist for the mill, this is what the compiler
> told
> me when I encouraged it to burble when it saw a default pattern in a
> catch clause. These are only the pure defaults, not including any
> additional "case e: Throwable" or "case e: Exception" which also
> exist.
>
> Some of these do really interesting stuff - here is a favorite:
>
> } catch {
> case e => throw new java.lang.IndexOutOfBoundsException(blah
> blah)
> }
>
> ClassPath.scala, line 337
> Code.scala, line 204
> CodeWriter.scala, line 132
> CodeWriter.scala, line 63
> ComboBoxes.scala, line 63
> Erasure.scala, line 1080
> FastScalac.scala, line 109
> Global.scala, line 184
> IdeSupport.scala, line 202
> IdeSupport.scala, line 310
> IdeSupport.scala, line 35
> IdeSupport.scala, line 39
> Inliners.scala, line 375
> Inliners.scala, line 75
> InteractiveReader.scala, line 24
> Interpreter.scala, line 794
> JLineReader.scala, line 21
> MainGenericRunner.scala, line 101
> MainGenericRunner.scala, line 118
> Manifest.scala, line 110
> MarkupParsers.scala, line 101
> MetaParser.scala, line 67
> ModelFrames.scala, line 388
> ModelToXML.scala, line 117
> Relation.scala, line 43
> Scalac.scala, line 684
> Scaladoc.scala, line 629
> ScriptRunner.scala, line 367
> ScriptRunner.scala, line 419
> ScriptRunner.scala, line 445
> SyncVar.scala, line 63
> Tests.scala, line 68
> Tuple.scala, line 31
> ZipArchive.scala, line 238
> ops.scala, line 33

David Pollak
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: concurrency time bombs: exception swallowing


On Tue, Apr 28, 2009 at 10:22 AM, Paul Phillips <paulp@improving.org> wrote:
On Tue, Apr 28, 2009 at 10:09:31AM -0700, David Pollak wrote:
> If you're going to go through a fix the exception management in the
> compiler, I'd suggest fixing the Scala exception hierarchy so that
> Errors are thrown in dire circumstances (e.g., out of memory) rather
> than simply a program logic error (e.g., MatchError).

MatchError calls itself Error, but it derives from RuntimeException.

I don't see any clear misuses of Error in trunk, but let me know if you
have specific examples I'm overlooking.

My mistake based on memories from Scala circa 2.4 days.  Sorry for the line noise.
 


--
Paul Phillips      | Eschew mastication.
Protagonist        |
Empiricist         |
slap pi uphill!    |----------* http://www.improving.org/paulp/ *----------



--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
mr. grabby-hands catch clause - full(ish) list

On Wed, Apr 29, 2009 at 05:58:17PM +0200, Gilles Dubochet wrote:
> It would be good to review problematic cases in the compiler and
> library. Paul, do you think you could encourage the compiler to burble
> in non-default cases too (and maybe stay silent when the exception is
> then thrown again), and post the resulting list.

Here is a longer list. This is not necessarily complete because it's
based purely on syntax -- it can easily be wrong in both directions
(extractors, guards, same-named types from different packages, calling
methods which themselves rethrow the exception, etc. etc.) but let us
hope people have not gone out of their way to make these harder to spot.

I looked for "Throwable", "Exception", "RuntimeException", and "Error".
First I'll post the list without apparent rethrows, then the whole list;
I can't be sure just from my naive syntax examination they're actually
rethrowing the incoming throwable and not a new one.

/** just non-rethrows **/

CLRTypes.scala catches RuntimeException at line 128
ClassfileParser.scala catches RuntimeException at line 93
ClassfileParser.scala catches Throwable at line 816
Code.scala catches Exception at line 223
Code.scala catches Exception at line 234
Code.scala catches Wildcard (All Throwable) at line 204
CodeWriter.scala catches Wildcard (All Throwable) at line 132
CodeWriter.scala catches Wildcard (All Throwable) at line 63
ComboBox.scala catches Exception at line 91
ComboBoxes.scala catches Wildcard (All Throwable) at line 63
CompileClient.scala catches Exception at line 126
CompileManager.scala catches Error at line 142
CompileManager.scala catches Exception at line 142
CompileServer.scala catches Throwable at line 129
CompileSocket.scala catches Exception at line 184
CompileSocket.scala catches Exception at line 220
CompileSocket.scala catches Exception at line 251
CompileSocket.scala catches Throwable at line 239
EncodingHeuristics.scala catches Exception at line 165
FastScalac.scala catches Throwable at line 109
FastScalac.scala catches Wildcard (All Throwable) at line 109
GenMSIL.scala catches Error at line 345
Global.scala catches Wildcard (All Throwable) at line 184
IdeSupport.scala catches Wildcard (All Throwable) at line 202
IdeSupport.scala catches Wildcard (All Throwable) at line 310
IdeSupport.scala catches Wildcard (All Throwable) at line 35
IdeSupport.scala catches Wildcard (All Throwable) at line 39
Inliners.scala catches Wildcard (All Throwable) at line 75
Interpreter.scala catches Wildcard (All Throwable) at line 791
JLineReader.scala catches Wildcard (All Throwable) at line 21
Main.scala catches Exception at line 102
Main.scala catches Exception at line 71
MainGenericRunner.scala catches Wildcard (All Throwable) at line 101
MainGenericRunner.scala catches Wildcard (All Throwable) at line 118
MarkupParsers.scala catches Wildcard (All Throwable) at line 101
MetaParser.scala catches Wildcard (All Throwable) at line 67
ModelFrames.scala catches Wildcard (All Throwable) at line 388
Models.scala catches Error at line 377
NetKernel.scala catches Exception at line 131
NewScanners.scala catches Exception at line 297
Reaction.scala catches Throwable at line 110
Relation.scala catches Wildcard (All Throwable) at line 43
SUnit.scala catches Throwable at line 96
Scalac.scala catches Throwable at line 684
Scalac.scala catches Wildcard (All Throwable) at line 684
Scaladoc.scala catches Throwable at line 629
Scaladoc.scala catches Wildcard (All Throwable) at line 629
ScriptRunner.scala catches Error at line 103
ScriptRunner.scala catches Wildcard (All Throwable) at line 360
SemanticTokens.scala catches Error at line 547
SemanticTokens.scala catches Throwable at line 510
SourceReader.scala catches Exception at line 55
TcpService.scala catches Exception at line 165
TcpService.scala catches Exception at line 274
TypeParser.scala catches RuntimeException at line 62
Worker.scala catches Exception at line 178
Worker.scala catches Exception at line 206
Worker.scala catches Exception at line 371
Worker.scala catches Exception at line 671
Worker.scala catches Exception at line 731
Worker.scala catches Exception at line 802
Worker.scala catches Throwable at line 867
ZipArchive.scala catches Wildcard (All Throwable) at line 238
ops.scala catches Wildcard (All Throwable) at line 33

/** and the whole list **/

CLRTypes.scala catches RuntimeException at line 128
ClassPath.scala catches Error at line 136 (but may rethrow it)
ClassPath.scala catches Wildcard (All Throwable) at line 337 (but may rethrow it)
ClassfileParser.scala catches RuntimeException at line 93
ClassfileParser.scala catches Throwable at line 816
Code.scala catches Exception at line 223
Code.scala catches Exception at line 234
Code.scala catches Wildcard (All Throwable) at line 204
CodeWriter.scala catches Wildcard (All Throwable) at line 132
CodeWriter.scala catches Wildcard (All Throwable) at line 63
ComboBox.scala catches Exception at line 69 (but may rethrow it)
ComboBox.scala catches Exception at line 91
ComboBoxes.scala catches Wildcard (All Throwable) at line 63
CompileClient.scala catches Exception at line 126
CompileManager.scala catches Error at line 142
CompileManager.scala catches Exception at line 142
CompileServer.scala catches Throwable at line 129
CompileSocket.scala catches Exception at line 184
CompileSocket.scala catches Exception at line 220
CompileSocket.scala catches Exception at line 251
CompileSocket.scala catches Throwable at line 239
Compiler.scala catches Exception at line 51 (but may rethrow it)
Database.scala catches Throwable at line 182 (but may rethrow it)
EncodingHeuristics.scala catches Exception at line 165
Erasure.scala catches Exception at line 684 (but may rethrow it)
Erasure.scala catches Wildcard (All Throwable) at line 1080 (but may rethrow it)
ExplicitOuter.scala catches Throwable at line 235 (but may rethrow it)
FactoryAdapter.scala catches Exception at line 288 (but may rethrow it)
FastScalac.scala catches Throwable at line 109
FastScalac.scala catches Wildcard (All Throwable) at line 109
GenMSIL.scala catches Error at line 345
GenMSIL.scala catches Exception at line 2386 (but may rethrow it)
GenMSIL.scala catches Exception at line 569 (but may rethrow it)
GenMSIL.scala catches Throwable at line 2052 (but may rethrow it)
Global.scala catches Error at line 142 (but may rethrow it)
Global.scala catches RuntimeException at line 142 (but may rethrow it)
Global.scala catches Wildcard (All Throwable) at line 184
IdeSupport.scala catches Error at line 133 (but may rethrow it)
IdeSupport.scala catches Error at line 618 (but may rethrow it)
IdeSupport.scala catches Wildcard (All Throwable) at line 202
IdeSupport.scala catches Wildcard (All Throwable) at line 310
IdeSupport.scala catches Wildcard (All Throwable) at line 35
IdeSupport.scala catches Wildcard (All Throwable) at line 39
Inliners.scala catches Wildcard (All Throwable) at line 375 (but may rethrow it)
Inliners.scala catches Wildcard (All Throwable) at line 75
InteractiveReader.scala catches Wildcard (All Throwable) at line 24 (but may rethrow it)
Interpreter.scala catches Wildcard (All Throwable) at line 791
JLineReader.scala catches Wildcard (All Throwable) at line 21
LambdaLift.scala catches Throwable at line 227 (but may rethrow it)
ListBuffer.scala catches Exception at line 151 (but may rethrow it)
ListBuffer.scala catches Exception at line 172 (but may rethrow it)
ListBuffer.scala catches Exception at line 182 (but may rethrow it)
ListBuffer.scala catches Exception at line 221 (but may rethrow it)
ListBuffer.scala catches Exception at line 252 (but may rethrow it)
ListBuffer.scala catches Exception at line 92 (but may rethrow it)
Main.scala catches Exception at line 102
Main.scala catches Exception at line 71
MainGenericRunner.scala catches Wildcard (All Throwable) at line 101
MainGenericRunner.scala catches Wildcard (All Throwable) at line 118
MarkupParsers.scala catches Wildcard (All Throwable) at line 101
MetaParser.scala catches Wildcard (All Throwable) at line 67
Mixin.scala catches Throwable at line 1028 (but may rethrow it)
ModelFrames.scala catches Wildcard (All Throwable) at line 388
ModelToXML.scala catches Throwable at line 110 (but may rethrow it)
ModelToXML.scala catches Wildcard (All Throwable) at line 117 (but may rethrow it)
Models.scala catches Error at line 377
NetKernel.scala catches Exception at line 131
NewScanners.scala catches Exception at line 297
Reaction.scala catches Throwable at line 110
Relation.scala catches Wildcard (All Throwable) at line 43
SUnit.scala catches Throwable at line 96
Scalac.scala catches Throwable at line 684
Scalac.scala catches Wildcard (All Throwable) at line 684
Scaladoc.scala catches Throwable at line 629
Scaladoc.scala catches Wildcard (All Throwable) at line 629
ScriptRunner.scala catches Error at line 103
ScriptRunner.scala catches Wildcard (All Throwable) at line 360
ScriptRunner.scala catches Wildcard (All Throwable) at line 412 (but may rethrow it)
ScriptRunner.scala catches Wildcard (All Throwable) at line 438 (but may rethrow it)
SemanticTokens.scala catches Error at line 275 (but may rethrow it)
SemanticTokens.scala catches Error at line 333 (but may rethrow it)
SemanticTokens.scala catches Error at line 435 (but may rethrow it)
SemanticTokens.scala catches Error at line 446 (but may rethrow it)
SemanticTokens.scala catches Error at line 547
SemanticTokens.scala catches Throwable at line 510
SourceReader.scala catches Exception at line 55
SyncVar.scala catches Wildcard (All Throwable) at line 63 (but may rethrow it)
TcpService.scala catches Exception at line 165
TcpService.scala catches Exception at line 274
Tests.scala catches Wildcard (All Throwable) at line 68 (but may rethrow it)
TreeCheckers.scala catches Throwable at line 125 (but may rethrow it)
TreeCheckers.scala catches Throwable at line 151 (but may rethrow it)
TreeCheckers.scala catches Throwable at line 66 (but may rethrow it)
Tuple.scala catches Wildcard (All Throwable) at line 31 (but may rethrow it)
TypeParser.scala catches RuntimeException at line 62
Typers.scala catches Exception at line 3499 (but may rethrow it)
Typers.scala catches Exception at line 838 (but may rethrow it)
UnCurry.scala catches Throwable at line 155 (but may rethrow it)
UnPickler.scala catches Throwable at line 46 (but may rethrow it)
Worker.scala catches Exception at line 178
Worker.scala catches Exception at line 206
Worker.scala catches Exception at line 371
Worker.scala catches Exception at line 671
Worker.scala catches Exception at line 731
Worker.scala catches Exception at line 802
Worker.scala catches Throwable at line 867
ZipArchive.scala catches Wildcard (All Throwable) at line 238
ops.scala catches Wildcard (All Throwable) at line 33

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