
Immutable annotations for Java - javinpaul
http://immutables.github.io/
======
carsongross
It is fascinating to watch how both the java and javascript communities deal
with the very different shortcomings of their respective programming
languages.

It is also horrifying.

~~~
unclebucknasty
Mutability isn't a shortcoming. It's a feature.

~~~
nmrm2
Immutability isn't a shortcoming. It's a feature. :-)

~~~
unclebucknasty
Hold on to that thought. I'll check back in with you in, say, 5 years. By
then, we should have all endured enough unnecessary pain to lurch back in the
other direction. :)

~~~
fnordsensei
We're well into the era where scarce computing resources no longer limits us
the way they used to. We're over some kind of hump with regards to that. Since
computing power is more abundant, the limiting factor we're currently running
into has to do with the cognitive overhead incurred by our current tools,
since tools always lag behind somewhat. Our current tools are primarily built
to be efficient with machine resources, but are not necessarily built to make
efficient use of cognitive resources.

As cognitive resources become the bottleneck, it's sensible to invest in tools
that decrease cognitive burden. So we're seeing an upswing in popularity with
methods and techniques aimed at limiting the amount of unnecessary, incidental
complexity generated. "Easier to use" is nice, but "less complex" is
imperative right now.

Immutability is one of those techniques that _can_ be leveraged to limit
growth of complexity.

~~~
unclebucknasty
> _Immutability is one of those techniques that can be leveraged to limit
> growth of complexity._

What you're saying is perfectly rational, right down to your emphasis on
_can_. I don't take exception to immutability as one tool. My problem is with
the notion that it is the _only_ tool and the corollary that mutability is
_always_ wrong.

------
guelo
There's a very similar library from Google
[https://github.com/google/auto/blob/master/value/README.md](https://github.com/google/auto/blob/master/value/README.md)

The one thing that tripped me up when I tried to use it is that you can't add
other library annotations. For example, I couldn't change the json serialized
field name using Gson's @SerializedName("custom_naming").

~~~
elucash
Maybe it's not what you looking for, but Immutables support binary [1] and
JSON serialization [2] (Jackson or Gson) very well including field naming
customization.

[1]
[http://immutables.github.io/immutable.html#serialization](http://immutables.github.io/immutable.html#serialization)

[2]
[http://immutables.github.io/json.html](http://immutables.github.io/json.html)

------
royjacobs
Hmm, this seems like a more heavyweight version of the immutable object
support in Lombok [1], through the @Value and @Builder annotations. The
website looks nicer than Lombok's, though :)

[1]
[https://projectlombok.org/features/index.html](https://projectlombok.org/features/index.html)

------
CHY872
This kind of thing has worried me a little in the past (Lombok is a similar,
but less focused project). My main concern is that this is not part of the
pluggable annotations standard; it's an undocumented API provided by Sun
javac. This means that it is prone to breakages, although I don't suppose it
will particularly soon.

I know that Lombok had to change their code quite frequently to fit with
different javac versions for a while, which means that this project becoming
stale could be a problem.

~~~
nothrabannosir
Could someone elaborate on the downvotes? I'm not the OP, but this sounds like
a valid concern.

What am I missing?

~~~
drrb
Perhaps because this project actually is using the Pluggable Annotation
Processing API (e.g.
[https://github.com/immutables/immutables/blob/master/generat...](https://github.com/immutables/immutables/blob/master/generator-
processor/src/org/immutables/generator/processor/Processor.java)).

~~~
CHY872
Yep, that's fair. I took another look, Lombok is only unsupported because it
inserts methods into pre-existing classes; I misremembered the limitation on
the pluggable annotations. My bad!

------
pron
BTW, Java now has pluggable type systems. One of them[1] adds true static,
compile-time checks for immutability, and allows method to specify that they
only receive immutable objects.

There are many others, including tainting types, linear types, physical unit
types and more.

[1]: [http://types.cs.washington.edu/checker-
framework/current/che...](http://types.cs.washington.edu/checker-
framework/current/checker-framework-manual.html#javari-checker)

------
stdbrouw
"the most full-featured and mature tool in this field!", "With Immutables you
can generate state of the art immutable object and builder."

A programming library with copy that looks like it's written by a marketeer –
well, why not, I guess :-)

------
Niten
Neat. It would be interesting to see a comparison between this and FreeBuilder
(as well as AutoValue, though I think the differences there are more obvious).

I'm all for tools that make immutability easier; the lack of immutable objects
is one of my main sources of cognitive dissonance when programming in Go
instead of Java.

~~~
elucash
Maybe it would not be an exhaustive comparison, but there's (biased enough)
feature matrix of Immutables, AutoValue, FreeBuilder: [1]

[1]
[http://immutables.github.io/CompareImmutables.pdf](http://immutables.github.io/CompareImmutables.pdf)

EDIT

------
iwwr
What's the advantage of that as opposed to the 'standard' java way of doing
immutable via 'final'?

~~~
quarterto
These aren't immutable _variables_ , they're immutable (i.e. persistent) _data
structures_. You can't directly change the objects themselves; instead,
"setters" create a new copy of the object.

~~~
dikaiosune
Perhaps I haven't had enough coffee yet, but could you explain how an
immutable data structure is any different than an object whose class
definition is all final? If you can't change any property of the object,
wouldn't that be the same as what this annotation does?

To be clear, it seems like a nice boiler-plate avoidance technique (which Java
could always use more of). But you're implying that there's some other
significant underlying problem this solves and I don't see it.

~~~
saryant
Java doesn't have immutable collections in its standard library. If if a
java.util.* collection is declared final, you can still modify its contents.

~~~
impl
Actually, it does, but they don't have explicit types. See
java.util.Collections.unmodifiableCollection(...), etc.

~~~
Someone
That still doesn't work all the way down. The objects you get out of the
collection remain as mutable as when they were inserted.

Also, _unmodifiableCollection_ doesn't make the collection you pass in
immutable; it creates a new object through which you can access it as long as
you don't modify it. Anybody holding a reference to the original object can
still change the object.

I think you can even somewhat break the collection by changing objects inside
it if doing that changes their hashcode (for sets and dictionaries, such a
change may have to reinsert the item in the collection to make sure that you
can still retrieve it)

~~~
impl
Right, but this project doesn't solve that problem, either. It wraps the
underlying collection in a builder to make it less easy to access, but it
doesn't appear that it places any additional restrictions on the types of
members or collection elements (from the generated code on their site anyway).

If you weren't using this library, you could achieve something similar with,
e.g.,

    
    
      someImmutableSet = Collections.unmodifiableSet(new HashSet<E>(someSet));
    

I think this library really is about making immutable objects accessible,
i.e., taking away the boiler plate. Hand-writing immutable (and potentially
mutable) implementations on top of interfaces for a whole set of DTOs is super
annoying.

------
unclebucknasty
One of the most frequently trumpeted cases for immutability is WRT thread
safety. Is it me, or does this need come up rarely in practice _relative to
the forcefulness of arguments to make everything immutable_? I get that it
depends on your project, etc. But, I'm talking overall.

There are other benefits to immutability, to be sure, but I appear to be the
rare voice that finds the dictum to "make everything immutable" to be
overstated. And, we seem to ignore the code bloat that comes along with it--
builders and the like, as well as performance implications.

Of course we solve the challenges that mutability can introduce by lopping it
off altogether, but at what cost? It's really not too far from solving
problems that object misuse can introduce by getting rid of objects.

Replace all setters with builders, annotations, etc. Do not ever change an
object's state. Ever! Run this Mutability Detector on your code to ensure you
are not allowing something to be mutable. At all costs, kill those language
features that allow object state to be changed!

At what point have we jumped the shark?

Maybe others believe in moderation as do I, and I just happen to be reading
more of the forceful champions of immutability lately. But, they seem pretty
loud and I have learned that edicts to never or always do something warrant
great suspicion.

~~~
lmm
Some language features are just bad and should be removed entirely. Moderation
is often the answer, but not always.
[https://xkcd.com/690/](https://xkcd.com/690/) .

> Of course we solve the challenges that mutability can introduce by lopping
> it off altogether, but at what cost? It's really not too far from solving
> problems that object misuse can introduce by getting rid of objects.

At what cost then? I can point to specific scenarios where objects are useful
and languages without them (e.g. Haskell) solve the problem less elegantly.
Can you say the same for mutability? Have you got a specific business problem
that you've solved with and without mutability and found that the mutability
made it better?

(FWIW my position is: no unmanaged mutability beyond method scope. Local
mutability is fine, but anything that crosses method boundaries should be
explicitly managed using e.g. State)

~~~
unclebucknasty
FWIW if you advocate managed local mutability, then you also have folks who
will tell you even that is evil. They would say internal mutability is still
mutability. And, of course, it's true that you do also have to manage the same
concurrency issues as with any mutability.

> _At what cost then?_

If a language offers a construct for achieving a certain goal, and you opt to
bypass that construct to create a parallel construct, then you are necessarily
creating additional cost. But, it's actually worse than that because it goes
beyond creation of parallel constructs: it also includes working to actively
suppress the built-in language constructs.

And now we are creating immutability tools and new annotations, and running
Mutability Detection, etc. as if mutability itself is a defect and stamping it
out automatically improves code quality.

> _Have you got a specific business problem that you 've solved with and
> without mutability_

Yes. Every bit of code I've written before the age of Mutability-is-Pure-Evil.
That code worked well without the additional code bloat, object copying, and
performance penalties associated with defeating natural language constructs.
No annotations. No builders everywhere. Just pure, clean, intuitive code
whereby other developers were required to actually understand the design
before using it.

You need to set a property? Then, set it. Don't construct a completely new
object with a builder, just to update the zip code. In a multithreaded
environment? Sorry, you need to understand concurrency issues. No amount of
dumbing down objects is going to make up for your lack of understanding there.

Otherwise, let's stop calling immutability OOP. What people really want is to
pass around a struct and have procedural code wrapped in other objects perform
operations on it.

And, sorry. Moderation is key. Your use of "internal mutability" is actually a
nod to moderation. When people find themselves repeating that something is
always evil, it should trip a mental alarm. Sure, there are cases wherein
immutability might be a reasonable way to solve a problem, but definitively
stating that it is always the right approach is shark-jumping.

~~~
lmm
> And, of course, it's true that you do also have to manage the same
> concurrency issues as with any mutability.

No, it's not. I'm talking about within a single method, which inherently means
belonging to a single thread.

> But, it's actually worse than that because it goes beyond creation of
> parallel constructs: it also includes working to actively suppress the
> built-in language constructs.

Again, some language constructs are just bad. E.g. I believe Gosling has said
he wishes he never put checked exceptions in Java.

> You need to set a property? Then, set it. Don't construct a completely new
> object with a builder, just to update the zip code. In a multithreaded
> environment? Sorry, you need to understand concurrency issues. No amount of
> dumbing down objects is going to make up for your lack of understanding
> there.

On the contrary, more restrictive models really are easier to understand.

~~~
unclebucknasty
> _I 'm talking about within a single method, which inherently means belonging
> to a single thread_

If your method is modifying data non-atomically, then you can still have
issues with data consistency when another thread attempts to access the object
in the middle of your update. You're going to need to synchronize access in
some manner.

> _Some language constructs are just bad...checked exceptions..._

Checked exceptions are not an integral part of OO design. Objects, along with
the concept of properties (i.e. state) are.

> _more restrictive models really are easier to understand_

That's simply not a universal truth.

~~~
lmm
> If your method is modifying data non-atomically, then you can still have
> issues with data consistency when another thread attempts to access the
> object in the middle of your update.

Externally-visible data should not be mutable.

> That's simply not a universal truth.

Let's talk specifics then. My preferred model is: every piece of persistent
(beyond a single method scope) mutable state is owned by an actor, and
accesses to that state are performed by sending State values to that actor and
receiving values back. The type system enforces that any state modification
happens in the appropriate actor; since State is an ordinary value you can
refactor safely without worrying that you're changing concurrency boundaries.
Monadic syntax (for/yield) makes it easy to compose state changes that should
happen atomically, and since the call to actually perform the modification is
explicit, it's easy to see which changes are atomic and which are not.

~~~
unclebucknasty
> _Externally-visible data should not be mutable._

This doesn't automatically solve the problem. If two threads invoke methods
which mutate (or read) the internal state, then inconsistencies can result if
not properly synchronized.

> _Let 's talk specifics_

You originally stated that more restrictive models are easier to understand.
My point is not that they never are (as in some universal truth). It's that
the real answer is that it depends. And, in the context of this discussion,
simply declaring that the restrictions that immutability imposes are
automatically beneficial to understanding is a non-sequitur.

But, WRT to the specifics you provided, your model may indeed provide
structure that can aid in understanding the code. But, I don't think it's the
degree of restrictiveness that determines this, as much as that there is
_some_ model in the first place. Of course, whether it's the best choice in a
given situation is a relative proposition.

Interestingly, however, you allow for mutability. And the real "magic" is
happening not through immutability alone, but careful assignment of mutability
operations _in conjunction_ with other concurrency idioms that you expect to
overlay atomicity.

So, essentially we agree: declaring mutability as the root of all evil is
overkill. Instead, the real prescription relies upon carefully
considered/managed mutability, used with the language's intended concurrency
features.

------
trask
In my experience, Immutables really helps address some of Java's verbosity
problem. Introducing it into my project cut 2,500 LOC (~10% of total code
base),
[https://github.com/glowroot/glowroot/commit/7bdd3ff](https://github.com/glowroot/glowroot/commit/7bdd3ff)

------
bhickey
If this is useful to you, check out the Mutability Detector
([https://github.com/MutabilityDetector/MutabilityDetector](https://github.com/MutabilityDetector/MutabilityDetector)).

------
istvan__
Scala, is that you?? :)

~~~
mark242
val immutableString = "foo"

val immutableList = List(1, 2, 3)

val immutableMap = Map("foo" -> "bar")

var mutableString = "foo"

val mutableList = collection.mutable.List(1, 2, 3)

val mutableMap = collection.mutable.Map("foo" -> "bar")

~~~
RyanZAG
No, this is not the same as the linked library. See here:
[http://stackoverflow.com/questions/6425165/statically-
decide...](http://stackoverflow.com/questions/6425165/statically-decide-if-a-
scala-class-is-immutable)

A similar example in Scala would be a class that has only 'val' types and no
'var' types, but read through the stackoverflow post to see the complexities.

~~~
mark242
case class Foo(bar: String, baz: String)

~~~
pron
Or in Kotlin:

    
    
        data class Foo(bar: String, baz: String)

------
fernandezpablo
Features: [...] MongoDB Integration.

WAT

------
hyperpape
So, I work at a company that uses Java for all its server-side technology (~2
million lines today), but we don't use annotations for code-gen. Can someone
explain to me why I would want to do that instead of a hypothetical IDE
feature/plugin?

~~~
jestar_jokin
Assuming you don't use annotations at all...

* DRY for cross-cutting concerns, like database transactions, logging, dependency injection, serialization, validation, web controllers/endpoints... basically, macros for Java.

* Less code means less chance for error - even if that code was generated at some point in the past, it will need to change in the future, and the future developer may do the change manually and might introduce mistakes. Using annotations can help enforce patterns.

~~~
hyperpape
We use annotations for some things, but they're either used at runtime for
configuration or things like the lovely @Deprecated.

~~~
jestar_jokin
Another advantage of using annotations to generate code at compile time, is
that any (simple) errors get detected at compile time instead of runtime. So,
potentially less tests you need to write.

------
molyss
immutability is some clear gap in java, but I'm curious on what immutable has
that checker framework [1] doesn't.

Looks like immutables transform the code in even more spaghettis.

Just looking at the "get started", it looks like the author voluntarily
ignores all the java conventions around variables and getters/setters.

I might be wrong on this, but I suspect this framework heavily relies on
introspection, which in my experience has always led to very hard to debug and
explore code.

[1] [http://types.cs.washington.edu/checker-
framework/](http://types.cs.washington.edu/checker-framework/)

~~~
elucash
>> what immutable has that checker framework doesn't.

Functionality overlap is not particularly clear with Checker framework, in
fact Immutable users often use Checker framework also. There are other tools
like AutoValue, FreeBuilder, Lombok where I can see more similarities, but
with important differences.

>> Looks like immutables transform the code in even more spaghettis.

I would not agree, but you should look at real world codebases like [1] or [2]
which use immutables.

>> Just looking at the "get started", it looks like the author voluntarily
ignores all the java conventions around variables and getters/setters.

Immutables support getters convention and you can configure any other
convention you have, see [3].

>> I might be wrong on this, but I suspect this framework heavily relies on
introspection, which in my experience has always led to very hard to debug and
explore code.

Immutables uses standard APIs of annotation processing. You can take a look at
example generated code [4].

[1] [https://github.com/facebook/buck](https://github.com/facebook/buck)

[2]
[https://github.com/glowroot/glowroot](https://github.com/glowroot/glowroot)

[3]
[http://immutables.github.io/style.html](http://immutables.github.io/style.html)

[4]
[http://immutables.github.io/generated.html](http://immutables.github.io/generated.html)

------
vbezhenar
I tried to use annotation processors, but they were very IDE-unfriendly.
According to the linked user guide it's better now. It's an interesting
alternative to runtime bytecode generators or proxies.

------
miguelrochefort
That's easy to do with Roslyn analyzers in C#.

~~~
CmonDev
...or just waiting for C# 7.

