Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Custom compiler warning

I've created a trait with some abstract procedures (methods returning Unit). I've then created a sub trait that puts in dummy implementations {} for the convenience of development. However I want to put a compiler warning on the dummy trait: "Using the dummy trait all functionality may not be implemented. Use the base trait in production."

I've looked at the Scala annotations and the Java annotations and I can't find an appropriate annotation or way of doing this. I could just make use of a deprecated annotation, but that's rather inelegant:

@deprecated("GraphicMethodsDummy contains procedure stubs. Inherit from GraphicMethods for production", "")

Inheriting from deprecated doesn't seem to have much advantage as the method that produces the compiler message seems to be private and can't be overridden.

like image 402
Rich Oliver Avatar asked Nov 02 '22 03:11

Rich Oliver


2 Answers

  1. Change your API so that the dummy trait can only be obtained through a "creator" method (e.g in a companion object).
  2. Implement the "creator method" as a def macro. It would look something like this:

class Dummy

object creator {
    def apply(): Dummy = macro creatorImpl

    def creatorImpl(c: Context)(): c.Expr[Dummy] = {
        import c.universe._

        c.warning(c.enclosingPosition,
            """Using the dummy trait all functionality may not be implemented. 
                        Use the base trait in production.""")

        reify(new Dummy)
    }
}

Note that an alternative, less involved way that is commonly used in various APIs (like Guava) is to just add a custom annotation to your class (e.g. @NotSafeForProd). However, this will of course not generate a compiler warning.

like image 146
mikołak Avatar answered Nov 08 '22 05:11

mikołak


If regular deprecation isn't good enough, how about rolling your own:

package scala {
  class noProd extends deprecatedInheritance("Provide an impl for production", since="forever")
}

package dummyonly {

  trait Abs { def f(i: Int): String }

  @noProd
  class Dummy extends Abs {
    def f(i: Int) = i.toString
  }
}

In a separate compilation unit:

//dummyonly2.scala:3: warning: inheritance from class Dummy in package dummyonly is deprecated: Provide an impl for production

package dummyonly {
  class Mine extends Dummy
}

Edit:

The privileged annotation is private to scala, but it's so useful that it's criminal to hide it under a bushel.

I don't really know, but the code comment reads:

// for now, this needs to be generalized to communicate other modifier deltas

or, to coin a phrase, WTF? I know what a "modifier" is, but a "modifier delta" is beyond my ken. The comment suggests, though, that the annotation might see broader access when they figure out how to make it work in a maintainable way.

I think there's supposed to be a semicolon instead of a comma, i.e., "for now; ...", but Scala programmers are so programmed to avoid semicolons that they avoid them even when grammatically correct.

like image 25
som-snytt Avatar answered Nov 08 '22 04:11

som-snytt