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

Re: Re: Why is scala.collection.parallel.CompositeThrowable a Throwable

6 replies
daniel
Joined: 2008-08-20,
User offline. Last seen 44 weeks 14 hours ago.
Knowing very little about any of these cases, I still feel the need to assert my uninformed opinion:

% ack 'extends Throwable'
compiler/scala/reflect/internal/FatalError.scala
6:case class FatalError(msg: String) extends Throwable(msg)

Should extend Error.
 
compiler/scala/reflect/internal/Symbols.scala
2264:  extends Throwable("Companions '" + sym1 + "' and '" + sym2 + "'
must be defined in same file") {

Seems like it should extend Error, but possibly Exception.
 
compiler/scala/reflect/internal/Types.scala
5628:  class TypeError(var pos: Position, val msg: String) extends
Throwable(msg) {
5632:  class NoCommonType(tps: List[Type]) extends Throwable(

Exception.

compiler/scala/tools/nsc/typechecker/Infer.scala
68:  private class NoInstance(msg: String) extends Throwable(msg) with
ControlThrowable { }

Should probably just extend ControlThrowable (see below).
 
library/scala/collection/parallel/package.scala
125:  extends Throwable("Multiple exceptions thrown during a parallel
computation: " + throwables.map(t => (t,
t.getStackTrace.toList)).mkString(", "))

I think this is the one we've been arguing about.
 
library/scala/runtime/Nothing$.scala
20:sealed abstract class Nothing$ extends Throwable

Nothing$ is never thrown (or caught), so I don't particularly care what it extends.

library/scala/util/control/ControlThrowable.scala
38:trait ControlThrowable extends Throwable with NoStackTrace

This one might be legit.  Again, we're talking about a separate category of exception, not an error, not a wrapped throwable, but something different.  Critically, we wouldn't want ControlException to be caught by anything except the code in the control structure, so this makes perfect sense to me.  What doesn't make sense is for NoInstance to pass a message to the Throwable(String) constructor.  ControlExceptions can carry data, but that data doesn't really make sense as exception data (e.g. message or stack trace).
 
library/scala/util/control/NoStackTrace.scala
19:trait NoStackTrace extends Throwable {

Since this is a marker trait usable on errors, exceptions and more, it makes sense to extend Throwable (though it might make more sense if it were a self-type, not sure).

Daniel
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: Why is scala.collection.parallel.CompositeThrowable a T

I wonder what was in the mind of the author of the java.lang.Error docs:

"An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch."

This doesn't apply to me! I only write unreasonable applications!

On 5/18/11 10:14 AM, Daniel Spiewak wrote:
> compiler/scala/reflect/internal/FatalError.scala
> 6:case class FatalError(msg: String) extends Throwable(msg)
>
> Should extend Error.

What is the benefit of FatalError extending Error. In the context of the compiler all it means is "the compiler cannot be run." Why should a reasonable application not wish to catch this? Either the catcher is code we wrote ourselves, like "Main" or "MainGenericRunner", in which case we don't need it to have any specific parent to recognize it. Or it is not, it is someone else with an embedded compiler, and we have now rendered ourselves type indistinguishable from such outcomes as "out of memory" and "machine on fire".

The compiler is a piece of software like any other, I don't know why it has special province to declare the world is ending just because things didn't go its way.

> library/scala/util/control/NoStackTrace.scala
> 19:trait NoStackTrace extends Throwable {
>
> Since this is a marker trait usable on errors, exceptions and more, it
> makes sense to extend Throwable (though it might make more sense if it
> were a self-type, not sure).

The trait extends Throwable so it can be used on all throwables, it doesn't have any more significance than that because it isn't a class. Here are some more which extend Throwable, just without saying so directly. But these have the great virtue of being distinguishable from other Throwable derivatives, which was what I created ControlThrowable for in the first place.

[paulp@stem src (master)]$ ack ControlThrowable
actors/scala/actors/Actor.scala
12:import scala.util.control.ControlThrowable
916:private[actors] class SuspendActorControl extends ControlThrowable

actors/scala/actors/Reaction.scala
13:import scala.util.control.ControlThrowable
16:private[actors] class KillActorControl extends ControlThrowable

actors/scala/actors/scheduler/QuitControl.scala
11:import scala.util.control.ControlThrowable
19:private[scheduler] class QuitControl extends ControlThrowable

compiler/scala/reflect/internal/Types.scala
15:import scala.util.control.ControlThrowable
3813: class MissingAliasControl extends ControlThrowable
3815: class MissingTypeControl extends ControlThrowable
5633: "lub/glb of incompatible types: " + tps.mkString("", " and ", "")) with ControlThrowable

compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
11:import scala.util.control.ControlThrowable
36: case object MissingEndTagControl extends ControlThrowable {
40: case object ConfusedAboutBracesControl extends ControlThrowable {
44: case object TruncatedXMLControl extends ControlThrowable {

compiler/scala/tools/nsc/doc/DocFactory.scala
6:import scala.util.control.ControlThrowable
89: object NoCompilerRunException extends ControlThrowable { }

compiler/scala/tools/nsc/interactive/CompilerControl.scala
8:import scala.util.control.ControlThrowable
322:class FreshRunReq extends ControlThrowable
327:object ShutdownReq extends ControlThrowable

compiler/scala/tools/nsc/interactive/Global.scala
14:import scala.util.control.ControlThrowable
956: class TyperResult(val tree: Tree) extends ControlThrowable

compiler/scala/tools/nsc/transform/SpecializeTypes.scala
954: case object UnifyError extends scala.util.control.ControlThrowable

compiler/scala/tools/nsc/typechecker/Infer.scala
11:import scala.util.control.ControlThrowable
68: private class NoInstance(msg: String) extends Throwable(msg) with ControlThrowable { }

compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
11:import scala.util.control.ControlThrowable

library/scala/runtime/NonLocalReturnControl.scala
13:import scala.util.control.ControlThrowable
15:class NonLocalReturnControl[T](val key: AnyRef, val value: T) extends ControlThrowable

library/scala/runtime/ScalaRunTime.scala
17:import scala.util.control.ControlThrowable
139: case e: ControlThrowable => throw e // don't catch non-local returns etc

library/scala/util/control/Breaks.scala
77:private class BreakControl extends ControlThrowable

library/scala/util/control/ControlThrowable.scala
23: * required ControlThrowables should be propagated, for
27: * import scala.util.control.ControlThrowable
32: * case ce : ControlThrowable => throw ce // propagate
38:trait ControlThrowable extends Throwable with NoStackTrace

library/scala/util/control/Exception.scala
43: case _: ControlThrowable => true
178: * catch whatever you ask of it: ControlThrowable, InterruptedException,

partest-alternative/scala/tools/partest/io/Logging.scala
7:import scala.util.control.ControlThrowable
80: case x: ControlThrowable => throw x

Todd Vierling
Joined: 2011-04-27,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Why is scala.collection.parallel.CompositeThrowable a T

On Wed, May 18, 2011 at 1:14 PM, Daniel Spiewak wrote:

[elided all compiler-internal stuff, only referring to public library API here]

>> library/scala/collection/parallel/package.scala
>> 125:  extends Throwable("Multiple exceptions thrown during a parallel
>> computation: " + throwables.map(t => (t,
>> t.getStackTrace.toList)).mkString(", "))
>
> I think this is the one we've been arguing about.

Exactly. And since it's the only bona fide case of this in the entire
library, I believe it should be revised to follow other art and be a
subclass of Exception -- as the intent is for it to be _catchable_. If
the intent is not to be caught (that is, it is a true failure of the
entire system), it should subclass Error. (I don't really care whether
it extends RuntimeException, so that's a debate best had separately.)

My previous statement, rephrased for Scala inheritance semantics,
still stands: All classes intended to be thrown should extend either
Exception or Error, never Throwable directly.

>> library/scala/runtime/Nothing$.scala
>> 20:sealed abstract class Nothing$ extends Throwable
>
> Nothing$ is never thrown (or caught), so I don't particularly care what it
> extends.

Right. Though my gut would say Error -- if it's ever somehow thrown by
JVM bytecode wrangling, it's an abort wanting to happen right there.
;)

>> library/scala/util/control/ControlThrowable.scala
>> 38:trait ControlThrowable extends Throwable with NoStackTrace

Is a trait and mixable, so extending Throwable is appropriate.

>> library/scala/util/control/NoStackTrace.scala
>> 19:trait NoStackTrace extends Throwable {

...same.

daniel
Joined: 2008-08-20,
User offline. Last seen 44 weeks 14 hours ago.
Re: Re: Why is scala.collection.parallel.CompositeThrowable a T

>     compiler/scala/reflect/internal/FatalError.scala
>     6:case class FatalError(msg: String) extends Throwable(msg)
>
> Should extend Error.

What is the benefit of FatalError extending Error.  In the context of the compiler all it means is "the compiler cannot be run." Why should a reasonable application not wish to catch this? Either the catcher is code we wrote ourselves, like "Main" or "MainGenericRunner", in which case we don't need it to have any specific parent to recognize it.  Or it is not, it is someone else with an embedded compiler, and we have now rendered ourselves type indistinguishable from such outcomes as "out of memory" and "machine on fire".

The compiler is a piece of software like any other, I don't know why it has special province to declare the world is ending just because things didn't go its way.

That seems reasonable.  I guess FatalError is not in fact a fatal error in the compiler (i.e. there's truly no way for it to proceed).  The answer here though depends on knowledge of the compiler's internals, of which I have none.  So, I will bow out here.

Daniel
extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Re: Why is scala.collection.parallel.CompositeThrowable a T

On 5/18/11 10:45 AM, Daniel Spiewak wrote:
> That seems reasonable. I guess FatalError is not in fact a /fatal/
> error in the compiler (i.e. there's truly no way for it to proceed).
> The answer here though depends on knowledge of the compiler's internals,
> of which I have none. So, I will bow out here.

The compiler's internals are not relevant.

Analogy: under what conditions should java.util.regex.Pattern throw
Errors? Its own specific Errors, not ones it induces by OOMing or something.

val p = new java.util.regex.Pattern("...")

I'm pretty sure the answer is "never" and I don't need to know much
about Pattern's internals to make that claim.

The compiler is no different[1].

// I am part of a completely different program
// I am not scalac
// I do not wish to see Errors which only mean this one instance
// of one class has encountered an unfortunate condition
val g = new scala.tools.nsc.Global(...)

[1] One could plausibly claim that certain extremely specific negative
outcomes in the compiler justify throwing an Error: the point would be
undiminished.

Aleksandar Prokopec
Joined: 2010-04-04,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Why is scala.collection.parallel.CompositeThrowable a T

I agree - that should be changed. In my view, CompositeThrowable should be deprecated, and CompositeException should be introduced instead (which holds a Seq of Exceptions).

One issue is what to do with Errors then. One solution is to pack them together with Exceptions in the CompositeException, but then we'd have to change the name to something else.

Alex


On 19/05/11 03:10, Josh Suereth wrote:
gEUY5WaCw [at] mail [dot] gmail [dot] com" type="cite"> I'd agree with the parallel collections exception handling bits throwing a subclass of Exception.   This is considered good Java practice, but I'd argue it's good JVM practice.
As for ControlException and the rest, I specifically think ControlException (and others like it) should *NOT* subclass Extension because they are never intended to be caught by user code, and would, in fact, break things as demonstrated by my scala-arm library (which wasn't ignoring them by default).
- Josh

On Wed, May 18, 2011 at 4:50 PM, Todd Vierling <tv [at] duh [dot] org" rel="nofollow">tv@duh.org> wrote:
On Wednesday, May 18, 2011 3:13:05 PM UTC-4, martin odersky wrote:
I agree that there's at least one problem then. Either it should catch all Throwables or be itself an Exception.

It should do both.
Catching all Throwables when repackaging from another thread parallels, e.g., java.util.concurrent.ExecutionException -- which repackages a Throwable (not Exception!) from another thread. If not everything is caught, you get involved in the fun world of Thread.UncaughtExceptionHandler, which is very likely not what you want.
As for inheritance, there's plenty of Java interop code (read: damn near *all* Java code) that assumes only Exception and Error (and their subclasses) exist as concrete instances in the wild. This is reason enough to me that directly extending Throwable is a bad choice for any concrete class.



Todd Vierling
Joined: 2011-04-27,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Why is scala.collection.parallel.CompositeThrowable a T
On Thursday, May 19, 2011 4:10:45 AM UTC-4, Aleksandar Prokopec wrote:
I agree - that should be changed. In my view, CompositeThrowable should be deprecated, and CompositeException should be introduced instead (which holds a Seq of Exceptions).

One issue is what to do with Errors then. One solution is to pack them together with Exceptions in the CompositeException, but then we'd have to change the name to something else.

Collecting Throwables as it does today, BUT changing it to extend Exception (or RuntimeException) instead of Throwable, would fix all the problems at once. At that point, the only semantic difference is the _name_ "CompositeThrowable", but I'd be fine with leaving that alone.
* Catching this object: As noted before, extending Exception, or a subclass of it, is sufficient to make common "catch" idioms do the correct thing. Don't extend Throwable directly. (Changing this after initial implementation does not break serialization.)
* Collecting both Exception and Error: For parallel exceptions, the caller wants to be able to catch "everything" that happened -- Exception and Error alike. Even in the case of an Error, it's safe to wrap that into an Exception delivered to another thread. That's precisely what java.util.concurrent.ExecutionException does: it wraps _any_ Throwable thrown by the background operation, even Errors.

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