
Pure4J: Compile-Time Functional Purity and Immutability for the Java Language - bobm_kite9
https://github.com/robmoffat/pure4j
======
riffraff
Wasn't there an @Immutable assertion in JSR-305? Why not reuse that?

EDIT: actually predating that JSR, coming from here
[http://jcip.net/annotations/doc/index.html](http://jcip.net/annotations/doc/index.html)

~~~
bobm_kite9
It's a good question. Originally, there were two reasons why I didn't do this.

First, the contract is slightly different, as I am also asserting purity. This
means that one @ImmutableValue knows that another @ImmutableValue (perhaps
from a library package) is pure. Whereas, a class annotated with @Immutable
might not be.

Second, I developed this with the bank I work in in mind. They are still on
flavours of Java 6 + 7.

However, I am currently in mind to port this to Checker Framework,
[http://types.cs.washington.edu/checker-
framework/](http://types.cs.washington.edu/checker-framework/) which is fully
supported by the JDK8 compiler.

I expect I'll still keep the separate annotation, but there are a lot of
benefits from a tooling point of view to doing this (IDE support, gradle etc)

~~~
pron
> I am currently in mind to port this to Checker Framework,
> [http://types.cs.washington.edu/checker-
> framework/](http://types.cs.washington.edu/checker-framework/) which is
> fully supported by the JDK8 compiler.

Awesome! Checker is _very_ promising. Unfortunately, its developers have not
yet (I think) turned their efforts into making it as easy to use as possible
(it could be made very easy to use, but that would take some effort).

------
Cieplak
The examples seem like they would consume a lot of memory, since every update
allocates a new object to the heap. Java's garbage collection solves this, but
does anyone know of an annotation or method to use to mark the old object as
unused so the runtime can deallocate the old object as soon as the new object
is created, rather than waiting for a stop-the-world gc pause? I guess a
better way to handle this would be to return a new object with most of the
attribute references unchanged, besides the updated fields.

~~~
bobm_kite9
So, rather than reinvent the wheel, I just ported the Clojure collections
over, added generics and made them more Java-ery [1]

In the Clojure world, (and indeed in Haskell and other pure-fp languages)
there is a lot more garbage collection. Rich Hickey makes a great case for
this trade off here [2].

On the JVM now very little of it is stop-the-world GC, it mostly does
incremental. It's been a while since I profiled a Java app in anger, but even
back on JDK5 this was the case, and I know they changed it significantly in
JDK7 to the G1 collector.. anyone have a clue about that?

[1]
[https://github.com/robmoffat/pure4j/blob/master/docs/tutoria...](https://github.com/robmoffat/pure4j/blob/master/docs/tutorial_collections.md)
[2] [http://www.infoq.com/presentations/Value-
Values](http://www.infoq.com/presentations/Value-Values) [3]
[http://www.oracle.com/webfolder/technetwork/tutorials/obe/ja...](http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html)

------
mystikal
How conservative is your analysis? Is it whole program? Do you look at the
class library? What's the largest size of program it handles in a reasonable
amount of time?

~~~
bobm_kite9
Great questions:

1\. Very conservative (I hope). As to exactly what this means, the specs are
here:
[http://robmoffat.github.io/pure4j/concordion/org/pure4j/test...](http://robmoffat.github.io/pure4j/concordion/org/pure4j/test/checker/spec/Index.html)

2\. Not the whole program, but "islands of purity". i.e. classes or
hierarchies of classes which are annotated with
@Pure/@ImmutableValue/@MutableUnshared (see above for what these mean,
exactly).

3\. At compile time, it builds a model of your software by analysing the byte-
code. It should run in linear time I guess but I haven't tried it on any huge
codebases yet. At runtime, the performance will be heavily dependent on the
performance of the Clojure collections that I've imported.

------
knocte
Nice! Immutability islands are the future.

~~~
bobm_kite9
Thanks! This was largely inspired by Frege
([https://github.com/Frege/frege](https://github.com/Frege/frege)) which has
been on HN before, but is worth checking out.

~~~
greydius
And Frege was based on Haskell which takes the exact opposite approach:
everything is pure/immutable by default, and extra effort is required to write
impure code and mutable data. What if we had a plugin that worked this way? It
would assume everything should be pure/immutable and require explicit
annotations (@Impure, @Mutable) otherwise. There are a lot of complications,
but it's food for thought.

~~~
bobm_kite9
A couple of people have suggested this idea - pure by default, as opposed to
impure by default. In Frege, as you point out, anything written in Haskell is
pure by default. However, if you want to call methods from libraries or the
JVM which are written in Java, then you have to tell Frege their level of
purity. So effectively, your Haskell code is the "island of purity" inside the
wider sea of impure Java runtime.

But yes, I think this is a workable idea - so long as there was some way of
identifying 3rd-party code purity instead of the annotation.

