An @impure annotation for functional programming in Scala

As an experiment — that’s a big emphasis on the word “experiment” there — I decided to create an @impure annotation for my current Scala project. The annotation is a “do nothing” annotation, so it doesn’t actually check the code in the way the @tailrec annotation works, for example.

What it does is serve to nag me. As I get into functional programming, my plan is to put the annotation on my impure Scala methods and functions as I create them. In theory it will bother me that they’re there, and then I’ll do something to try to make them pure.

Another use is that it serves as a way to make sure that I know that certain functions are impure. For instance, in my universe, I/O functions are always impure, so @impure can possibly serve as a way to tag impure I/O functions (a little like returning IO in Haskell functions, but in this case just a very experimental tag).

A simple example

As a simple example, I might write a Scala class like this, forcing myself to put the @impure annotation before the randomInt method definition:

class Numbers {
    @impure
    def randomInt(): Int = scala.util.Random.nextInt
}

This is a trivial example, but as mentioned there are two possible benefits of this:

  1. It makes it clear to anyone who looks at the method signature or Scaladoc that this method is impure.
  2. If there’s some way to make the function pure in the future (such as when I learn more about FP), I can come back and re-work the function then.

Of course the big technical downfall of this experiment is that there’s nothing to force me to use this annotation. So I’m going with the “Scout’s Honor” method of enforcement. I’m hoping that this “first idea” might spark another idea somewhere along the line.

Creating the Scala annotation

Creating the annotation in Scala is easy. Here’s the entire code required to define the annotation:

package com.alvinalexander.annotations

import scala.annotation.meta._

/**
 * An annotation that designates that a method is an "impure" function,
 * i.e., that its result depends on something more than its input parameters,
 * or that it has one or more external side effects.
 */
class impure extends scala.annotation.StaticAnnotation

You may also be able to create Scala annotations using macros, though I haven’t looked at those details.

For about two seconds I thought about creating a @pure annotation, but since my code should be 80-90% or more “pure” with the rest being impure, I quickly decided against that. So as a rule, my methods/functions will be pure unless otherwise annotated.

A Scala annotation that takes parameters

You can also define a Scala annotation that takes parameters. For example, this is the definition of the @deprecated annotation in the Scala 2.10.x code base:

import scala.annotation.meta._

/** 
 * An annotation that designates that a definition is deprecated.
 * Access to the member then generates a deprecated warning.
 *
 * @param message the message to print during compilation if the definition is accessed
 * @param since a string identifying the first version in which the definition was deprecated
 * @since 2.3
 */
@getter @setter @beanGetter @beanSetter
class deprecated(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation

(Here’s a link to the “deprecated” class.)

Using my @impure annotation

Getting back to my @impure annotation, here are two more examples of how to use it. All you really have to do is (1) import it, and then (2) put it before your method definitions:

package annotations

// [1] import it
import com.alvinalexander.annotations.impure

object AnnotationsTest extends App {

    var age = 42
 
    addToAge(1)
    echo("hello")

    // [2] use it
    @impure def addToAge(i: Int) { age += i }
    @impure def echo(s: String) { println(s) }
 
}

A Java version of the annotation

As a “note to self” more than anything else, you can also create the annotation in Java, like this:

package com.alvinalexander.annotations;

// needed for @Documented
import java.lang.annotation.*;

@Documented
public @interface impure {}

Annotations resources

Here are a few links to some Java and Scala annotations tutorials:

Summary

In summary, as I mentioned, I have no idea whether this is a good idea or not, it’s just an experiment. The idea has just been in the back of my mind for a while, so I thought I’d do the “simplest thing that could possibly work” and give it a try. Whether or not it bugs me enough to make my code more “functional” (by guilt), only time will tell.