Writing Custom Wart for Scala

Tapan Vaishnav
Sep 6 · 3 min read

Recently, I started working with Scala and even though Scala is such a powerful language having some strong features like Functional programming paradigm, pattern matching, Mixins, etc, also has some nastiest features like Inference issues, type-safety breaking, etc. Not just these, Scala having a steep learning curve makes it hard for programmers to always maintain the code quality.

But not to worry, here comes the WartRemover, to the rescue from some of these warts.

Now the question arises, What’s WartRemover?

Well, to answer in a simple way, WartRemover is a flexible Scala code linting tool. It takes the pain out of maintaining the scala code quality by removing some of the language warts and improves the reliability of your code.

Most of the common warts are already available in the following link

https://www.wartremover.org/

and in this article, we will be creating one custom wart.

Layered Architecture (image taken from a blog of herbertograce)

Now, while working with the Layered architecture, it’s hard to maintain the clear separation between layers and sometimes, developers are prone to call the methods or objects of some layer into the same layer.

So, to prevent that, we will be writing a custom wart to constraint the calls between the same layers.

  1. Create a Scala Project
  2. Import the wartremover into the project/plugins.sbt file
addSbtPlugin(“org.wartremover” % “sbt-wartremover” % wartremoverVersion)

3. Add following warts settings in the build.sbt file

Each time generating the wart jar file and passing classpath to the project is cumbersome so we will add the above settings to automatically generate the jar file and to be available at the time of compilation.

4. Create custom wart file named LayerControl.scala

5. Add two services classes named as ExistingService.scala and NewService.scala under the service project with the following contents.

package servicesclass NewService {  
val test1 = ExistingService
}
package services @Singleton
class ExistingService {
def someFunction[A]: Unit = println("print some message")
}

6. Run sbt compile

We can see from the above that our layer control wartremover is working well and generating the corresponding warning. We can change the log level from warn to error by changing the wartremoverWarnings += to wartremoverError+= in build.sbt file.

7. Let’s also create some test cases for our LayerControl wart.

We will be using the FunSuite for testing and to get aid for testing wartUniverse, we can use the ResultAssertions class, which can be found in the original repo.

https://raw.githubusercontent.com/wartremover/wartremover/master/core/src/test/scala/wartremover/ResultAssertions.scala

Finally, for layer constraint, even if we check the ClassDef (checking extends and mixins), we won’t find any anomaly as methods from the same module can be accessed directly, hence this article uses the ValDef to detect the wart. But ClassDef can be used in other cases.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade