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

@conditional annotation now implemented

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

I didn't fully appreciate the goodness of the idea at the time, but it
was a very good idea.

Here is what I have working. One thing I was thinking is that it might
be nice to be able to define what an elided method is replaced with from
the annotation. Right now with @conditional you get a zero based on the
return type of the removed method (which means (), false, 0, or null
pretty much.) But to specify a value in the same annotation I'd have to
add a type parameter and a field which is not appealing as it's nice and
clean as is. Another annotation? What do you think?

And how's this look otherwise?

// include at Info level; exclude Symbol and Tree
% scalac -Xinclude cond.Info -Xexclude cond.Symbol,cond.Tree -d /tmp test/files/run/conditional-ann.scala

// running program
% scala -cp /tmp Test
[types] fatal: oh noes
[types] warning: kind of important
[types] info: hello

// generated bytecode - 15 calls become 3
public void main(java.lang.String[]);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: invokevirtual #35; //Method typeLogger:()LTest$CategoryLogger;
4: ldc #37; //String oh noes
6: invokevirtual #43; //Method Test$CategoryLogger.fatal:(Ljava/lang/String;)V
9: aload_0
10: invokevirtual #35; //Method typeLogger:()LTest$CategoryLogger;
13: ldc #45; //String kind of important
15: invokevirtual #48; //Method Test$CategoryLogger.warning:(Ljava/lang/String;)V
18: aload_0
19: invokevirtual #35; //Method typeLogger:()LTest$CategoryLogger;
22: ldc #50; //String hello
24: invokevirtual #53; //Method Test$CategoryLogger.info:(Ljava/lang/String;)V
27: return

// full test case
import annotation._

package cond {
trait Trace
trait Debug extends Trace
trait Info extends Debug
trait Warning extends Info
trait Fatal extends Warning

trait Symbol
trait Type
trait Tree
}

object Test {
import cond._

class CategoryLogger[T](categoryName: String) {
@conditional[Fatal with T] def fatal(msg: String) = println("[" + categoryName + "] fatal: " + msg)
@conditional[Warning with T] def warning(msg: String) = println("[" + categoryName + "] warning: " + msg)
@conditional[Info with T] def info(msg: String) = println("[" + categoryName + "] info: " + msg)
@conditional[Debug with T] def debug(msg: String) = println("[" + categoryName + "] debug: " + msg)
@conditional[Trace with T] def trace(msg: String) = println("[" + categoryName + "] trace: " + msg)
}

val typeLogger = new CategoryLogger[Type]("types")
val symbolLogger = new CategoryLogger[Symbol]("symbols")
val treeLogger = new CategoryLogger[Tree]("trees")

def main(args: Array[String]): Unit = {
typeLogger.fatal("oh noes")
typeLogger.warning("kind of important")
typeLogger.info("hello")
typeLogger.debug("relevant info")
typeLogger.trace("extraneous info")

symbolLogger.fatal("oh noes")
symbolLogger.warning("kind of important")
symbolLogger.info("hello")
symbolLogger.debug("relevant info")
symbolLogger.trace("extraneous info")

treeLogger.fatal("oh noes")
treeLogger.warning("kind of important")
treeLogger.info("hello")
treeLogger.debug("relevant info")
treeLogger.trace("extraneous info")
}
}

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