5 ms·
Pure4J: Compile-Time Functional Purity and Immutability for the Java Language
- knocte 11y agoNice! Immutability islands are the future.
- bobm_kite9 11y agoThanks! 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 11y agoAnd 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 11y agoA 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.
- riffraff 11y agoWasn'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 11y agoIt'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 11y ago> 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).
- deleted 11y ago[deleted]
- mystikal 11y agoHow 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 11y agoGreat 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/checker/spec/Index.html http://robmoffat.github.io/pure4j/concordion/org/pure4j/test... 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.
- Cieplak 11y agoThe 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.
- Cieplak 11y agoTo attempt to answer my own question about marking objects for deletion, it seems like there aren't a lot of options besides making sure there aren't outstanding references to the dead object: http://stackoverflow.com/questions/11332239/is-it-possible-to-mark-java-objects-non-collectable-from-gc-perspective-to-save http://stackoverflow.com/questions/11332239/is-it-possible-t... http://stackoverflow.com/questions/5331422/marking-an-object-to-be-removed-in-the-gc http://stackoverflow.com/questions/5331422/marking-an-object...
- bobm_kite9 11y agoSo, 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/tutorial_collections.md https://github.com/robmoffat/pure4j/blob/master/docs/tutoria... [2] http://www.infoq.com/presentations/Value-Values http://www.infoq.com/presentations/Value-Values [3] http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html http://www.oracle.com/webfolder/technetwork/tutorials/obe/ja...