Allows the enforcement of purity in methods/functions. A function is pure if: - it does not call an impure function - does not read a var defined outside the function - does not assign to a var defined outside the function - perform any interaction with the 'world' (which is basically an impure action) -> is referential transparent (always the same output for the same input) A pure method can only be overridden by a pure method, overriding pure methods with impure methods is not allowed. There are two possibilities to declare a method as impure: def println(s: String): Unit @sideEffect or @impure def println(s: String): Unit Both variants are equal, there are no difference between them. The compiler can infer the impurity of a method if the last statement of the method body is a call to an impure method. def hello = println("Hi there) // inferred to 'def hello: Unit @sideEffect' Methods that would be considered impure according to the rules above can be declared as pure by the developer. The compiler will not check if those methods really are referential transparent or cause no side effects, this is the responsibility of the developer. Use this syntax to declare a method as pure @declarePure def log(s: String) { println("LOG "+s) } For methods that make use of type parameters that purity might depend on the purity of those parameters. This is specified using the @impureIf annotation: @impureIf('B) def exec[B](f: () => B): Unit = f() The @impureIf annotation might reference any of the type parameters that can be used inside the method. If the method returns a parameterized type, then that type is automatically used as @impureIf if no purity annotation is used: def exec[B](f: () => B): B = f() //equals @impureIf('B) and @impureIfReturnType A Constructor is considered a normal method, but is annotated on the class itself. The @impure and @declarePure annotations can be used. Example: @impure class MyClass { println("Hi") // impure call } LIMITATIONS: - Type Parameter on methods that take impure functions as parameter may need to be specified explicitly - see HigherLevelFunctionsWithInferenceTest - Problem seems to be within the Scala inferencer, on m[A](f: Function[String,A]): A that is called with val f: String => Int @sideEffect = it _ infers A to Int instead of Int @sideEffect. The only calls to the AnnotationCheckers are to annotationsConform(), where we can't fix the problem.