Help to understand NoStackTrace trait and object

Can someone help me understand the code in NoStackTrace.scala ?
There is a trait defined named NoStackTrace which I’m using in my code as follows.


  def block[A](body:(A=>Nothing)=>A):A = {
    // CL like block/return, the name of the return() function is provided
    //  by the caller.
    //  Usage:  block{ ret =>  ... ret(someValue) ...}

    // extending Exception with NoStackTrace prevents throwing the
    // exception from computing the stacktrace and storing the information.
    // We don't need a stacktrace because the purpose of this exception
    // is simply to perform a non-local exit.
    import scala.util.control.NoStackTrace

    class NonLocalExit(val data:A) extends Exception with NoStackTrace {}
    def ret(data:A):Nothing = {
      throw new NonLocalExit(data)
    }
    try{
      body(ret)
    }
    catch{
      case nonLocalExit: NonLocalExit => nonLocalExit.data
    }
  }

The purpose is to prevent the java fillInStackTrace method from begin called when a particular exception is constructed. However, the code in the trait definition has some exception to this rule (no pun intended) based on sys.SystemProperties.noTraceSupression.

What’s the idea behind scala.sys.SystemProperties and why is that built into this trait as a backdoor?

Here is the code I see in NoStackTrace.scala when I jump to there in IntelliJ.


/** A trait for exceptions which, for efficiency reasons, do not
 *  fill in the stack trace.  Stack trace suppression can be disabled
 *  on a global basis via a system property wrapper in
 *  [[scala.sys.SystemProperties]].
 *
 *  @note Since JDK 1.7, a similar effect can be achieved with `class Ex extends Throwable(..., writableStackTrace = false)`
 *
 *  @author   Paul Phillips
 *  @since    2.8
 */
trait NoStackTrace extends Throwable {
  override def fillInStackTrace(): Throwable =
    if (NoStackTrace.noSuppression) super.fillInStackTrace()
    else this
}

object NoStackTrace {
  final def noSuppression = _noSuppression

  // two-stage init to make checkinit happy, since sys.SystemProperties.noTraceSuppression.value calls back into NoStackTrace.noSuppression
  final private var _noSuppression = false
  _noSuppression = sys.SystemProperties.noTraceSuppression.value
}

scala.sys.SystemProperties wraps access to the Java system properties (accessed through java.lang.System.getProperties(), see the Javadoc or the Java tutorial). Some properties are set automatically by the JVM (like the Java version, etc.) but others can be set either programmatically or with a command-line option -Dpropertyname=value when launching the JVM (when running from SBT, you can add the command-line option to the javaOptions configuration key).

My guess is that this is done this way to allow JVM-wide configuration of the behavior without changing the code - juste launch your app with the correct command-line option if you need to see those stacktraces for debugging?

Edit: the property used is scala.control.noTraceSuppression, so you would enable it with the command-line option -Dscala.control.noTraceSuppression=true.

1 Like