[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: the benefits of immutability

Michael St . Hippolyte wrote:

> > Have you read the example I cited earlier:

 > > http://courses.dce.harvard.edu/~cscie160/EffectiveJava.htm
 > Thanks for the reference, I missed it the first time.  As I see it,
 > in the example it uses to make its argument (InstrumentedHashSet)
 > the real culprit is not inheritance but mutability...  I would be
 > curious to see if anyone can come up with a similar example showing
 > broken behavior when functional restrictions are in place,
 > i.e. objects are immutable and methods are side-effect free.

Sure thing.  Here's an example that exhibits the same problem, even
though all the defined classes are immutable and their methods are
side-effect free

    public interface IPinhead {

         * Returns a pinhead that contains all of the angels contained
         * in this pinhead plus the additional angel passed in as a
         * parameter.
        IPinhead add(Angel angel);

         * Works like {@link #add(Angel)}.  The returned value
         * contains all of the angels in this pinhead plus the
         * additional angels passed in the <code>angels</code> array,
         * if any.
        IPinhead addAll(Angel[] angels);

    public class Pinhead implements IPinhead {
        private final Set m_angels;

        public Pinhead() {
            m_angels =  new HashSet();

        protected Pinhead(Collection angels, Angel angel) {
            m_angels = new HashSet(angels);

        private IPinhead _add(Angel angel) {
            return new Pinhead(m_angels, angel);

        public IPinhead add(Angel angel) {
            return _add(angel);

        public IPinhead addAll(Angel[] angels) {
            IPinhead result = this;
            for (int ii=0; ii<angels.length; ii++) {
                result = add(angels[ii]);
            return result;

    public final class InstrumentedPinhead extends Pinhead {
        private int m_count;

        public InstrumentedPinhead() {
            m_count = 0;

        public IPinhead add(Angel angel) {
            return super.add(angel);

        public IPinhead addAll(Angel[] angels) {
            m_count += angels.length;
            return super.addAll(angels);

        public int getCount() {
            return m_count;

I guess you could argue that mutability has not been completely
eliminated in this example.

An alternative way to look at it is to notice that the real culprit is
self-use.  The implementation of the "addAll" method in the Pinhead
class makes use of the (public) method "add" defined in the same
class.  In this particular case, self-use can be easily eliminated.
Replace "add" with "_add" in the implementation of "addAll".  In cases
where self-use cannot be eliminated, it must be documented.  (In other
words, you must disclose certain implementation details for some of
the methods in your externally exported API, thus potentially breaking