7

In C++ I can write:

#ifdef DEBUG
cout << "Debugging!" << endl;

Is there any equivalent in Scala?

Beryllium
  • 12,808
  • 10
  • 56
  • 86
Lai Yu-Hsuan
  • 27,509
  • 28
  • 97
  • 164
  • 2
    possible duplicate of [Debug log in Scala with no performance impact](http://stackoverflow.com/questions/12044054/debug-log-in-scala-with-no-performance-impact) – senia May 29 '13 at 17:26
  • By the way JVM and it's JIT usually do a pretty good job with eliding dead code, thus most likely simple `final val DEBUG = false` and `def log(str: String) = if (DEBUG) print(str)` should be enough for the most cases. – om-nom-nom May 29 '13 at 17:33

3 Answers3

10

The conventional idiom is @elidable.

The scaladoc covers your conventional use case:

http://www.scala-lang.org/api/current/scala/annotation/elidable.html

vossad01
  • 11,552
  • 8
  • 56
  • 109
som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • Probably no one uses elidable except indirectly in Predef.assert, but never actually eliding anything. As in the comment, `if (DEBUG)` where the flag is `final val` (with inferred type only) or `val DEBUG: true = true` guarantees simple elimination. – som-snytt Jun 10 '21 at 21:28
7

The equivalent form of a C preprocesser #ifdef is a Scala macro:

package app.macros.log

import scala.language.experimental.macros

import reflect.macros.Context

object SimpleMacroLogger {
  private val on = true

  def info(msg: String): Unit = macro info_impl

  def info_impl(c: Context)(msg: c.Expr[String]): c.Expr[Unit] = {
    import c.universe._

    if (on) {
      reify {
        println(msg.splice)
      }
    } else {
      reify {
        // Nothing
      }
    }
  }
}

to be used with

import app.macros.log.{SimpleMacroLogger => log}

object SimpleMacroLoggerDemo extends App {
  log.info("Hello")
}

It's far more complex to code, but it's usage is superior: There is no need for surrounding #ifdef/#endif etc. So it does not clutter up your code.

If you set on to false, the macro removes the logging completely.

Anything within the reify will go into the resulting byte code, the other code is run at compile time. This especially applies to the if (on) ....

Beryllium
  • 12,808
  • 10
  • 56
  • 86
0

If you want the code to only be executed when certain conditions hold, you can use a standard if block:

if (SystemProperties.get("debug.mode").exists(_ == "true") {
  println("Debugging!")
}

If you're concerned for whatever reason that the statement shouldn't even appear in the compiled output, then you can use an if-block with a compile-time constant expression. In these cases, javac/scalac will correctly infer that the condition will never be true, and so doesn't even include the bytecode for the block. (Obviously you'll need to modify your build to pull in a constant "true" for debug builds, and "false" for prod builds.)

object Constants {
    final val DEBUG = false
}

// ...

if (Constants.DEBUG) {
  println("Debugging!")
}
Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228