Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4617197
Votes 58
Synopsis RFE: Add Immutable types to Java
Category java:specification
Reported Against 1.2.1 , merlin-beta3
Release Fixed
State 6-Fix Understood, request for enhancement
Priority: 5-Very Low
Related Bugs 4229200 , 4910043 , 4211070
Submit Date 21-DEC-2001
Description




FULL PRODUCT VERSION :
All, e.g.

java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build
1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)

FULL OPERATING SYSTEM VERSION : all


ADDITIONAL OPERATING SYSTEMS : all



EXTRA RELEVANT SYSTEM CONFIGURATION :
This is an RFE for the langauage itself, therefore it
applies to all versions.

A DESCRIPTION OF THE PROBLEM :
Currently Immutable types can be hand coded in Java and are
very useful, e.g. String, Integer, also see "Effective
Java" Item 13: Favour Immutability. However they are: not
compiler enforced, you can't test for immutability, their
are no companion mutable classes derived from a common base
class, and the JVM doesn't know they are immutable and
therefore can't fully optimise them (e.g. eliminate
pointers for small objects, aggregate into arrays, assume
 customer  not changed by another thread, assume  customer  same
between JVMs and JVM invocations). Hand coded immutability
can be tricky; see Workaround section below, in particular
points J and K.

This proposal is to add an interface to mark a class as
immutable (note immutability on a per class basis not a per
 customer  basis) and to add immutable and companion mutable
classes plus two helper interfaces for conversion to/from
immutable and mutable. In particular make a new package
java.lang.immutable containing:

    public interface Immutable { /* Empty */ }
    public interface ToMutable extends Immutable {
        Object toMutable();
    }
    public interface ToImmutable {
        Immutable toImmutable();
    }

    public abstract class AbstractArray { ... }
    public class Array<ToMutable T> extends AbstractArray
                                implements ToMutable { ... }
    public class MutableArray<ToImmutable T>
        extends AbstractArray implements ToImmutable { ... }

    public abstract class AbstractString { ... }
    public class String extends AbstractString
                                implements ToMutable { ... }
    public class MutableString extends AbstractString
                              implements ToImmutable { ... }

    public abstract class AbstractInteger { ... }
    public class Integer extends AbstractInteger
                                implements ToMutable { ... }
    public class MutableInteger extends AbstractInteger
                              implements ToImmutable { ... }

    ...

Compiler extensions for classes that implement Immutable
--------------------------------------------------------
1. Make class final, if not already
2. Make all fields final, if not already
3. Make all fields private, if not already (not strictly
   necessary)
4. Only allow fields to be an Immutable inherited type or
   primitive
5. a==b maps to a.equals(b)
6. The compiler generates equals() and hashCode(), if not
   provided
7. The compiler generates clone() and toString(), if not
   provided
8. The type returned by clone() is the type of the class,
   not Object
9. Only inherit from classes without non-static fields or
   from interfaces
10. Automatic boxing/unboxing when casting to/from super
    types
11. Immutable objects must be initialised
12. Immutable objects cannot be compared to or assigned null
13. Mark class as immutable for JVM
14. Compiler provides a readResolve() method if necessary

Compiler and source code compatibility issues
---------------------------------------------
If code written for a compiler that understands Immutable
is accidentally given to a pre-Immutable compiler it might
compile producing spurious code. Probably not a major
problem in practice, similar problems in the past have
occurred (e.g. when Serializable was added) and these have
not proved to be serious.

JVM issues
----------
The proposal would be compatible with existing JVMs. An
unused modifier bit in the class description in the class
file would be set by the compiler to tell the JVM that the
class is immutable. Future JVMs could do more optimisation
 customer  that the Object is immutable. For example: small
immutable objects could be stack allocated and copied in
and out of methods and immutable objects could also be
aggregated into arrays, thus eliminating arrays of
pointers. Immutable Objects would enable the JVM to pass
them to threads without having to worry about memory
synchronization issues. JVM would know an immutable  customer 
is the same between JVM invocations and between JVMs.

Related proposals
-----------------
1. This proposal builds on: immutable keyword proposal from
   James Gosling http://java.sun.com/people/jag/FP.html (it
   is with some trepidation that I suggest that a proposal
   from James Gosling can be improved upon!). This proposal
   doesn't require a new keyword, it allows testing for
   immutability (x instanceof Immutable), takes into
   account liasing and security problems due to
   serialization, implements a truly immutable type (fields
   are Immutable or primitive in this proposal), and the
   James Gosling proposal allowed inheritance from objects
   that define fields and therefore you can't write an
   equals method and in turn == wouldn't work
   (see "Effective Java" Item 7).

2. This proposal is suggested as a better alternative than
   adding C/C++ style const keyword (RFE: 4211070). C/C++
   const has liasing problems and the syntax is poor, this
   proposal rectifies these deficiencies.

3. The proposal also overlaps with User-Defined Lightweight
   Value-Semantics Objects (RFE: 4213096) which are in C#
   as struct objects. The disadvantage of C# style struct
   objects are that they can lead to excessive copying, a
   problem seen in C++ also. Immutable objects never HAVE
   to be copied, it is up to the JVM, and therefore this
   problem is eliminated. C# struct objects do not help
   with memory synchronisation issues in multi-threaded
   applications, unlike immutable objects. You can't rely
   on C# struct objects between JVMs or between JVM
   invocations.

4. Other immutable proposals: RFEs 4037498 and 4395140 asks
   for immutable on a per  customer  not per class basis and
   therefore need a runtime check, this proposal doesn't.
   RFEs 4069541 and 4213096 are similar but don't address
   all the issues this proposal addresses.

5. Design be contract (DBC) is often used to give
   immutability in languages that support DBC, but I would
   argue that immutable types are more useful than DBC,
   simpler to implement, and don't incur runtime penalties
   (in fact quite the opposite). For immutable types you
   just check the arguments to the  constructor, therefore
   there is no need for DBC with immutable types. Note
   inheritance of checks automatically happens because
   derived types call super. DBC is a requested feature for
   Java, see RFE 4449383.

Design decisions explained
--------------------------
The proposal makes fields private, this isn't necessary for
an immutable type but I think it is  customer  practice and hence
its inclusion.

You can't write equals() if you allow inheritance of non-
static fields, see "Effective Java" Item 7, therefore
inheritance of non-static fields is not allowed.

Also it doesn't make sense to inherit from an  customer  that
has state since the state of the super  customer  is part of
the derived objects state and therefore the super class
needs to be Immutable and therefore you can't inherit from
it (Immutable classes need to be final). Instead use
composition, see "Effective Java" Item 7.

The compiler does automatic boxing and unboxing when
casting to and from a super type, this automatic boxing is
not in a hash-consing manner. In particular: ((Object)
immutable)==((Object)immutable) is false. Although it would
be nice to be hash-consing when boxing, the overhead is too
great.

The purpose of the ToImmutable and ToMutable interfaces and
allowing inheritance from objects without non-static fields
is to encourage the following immutable/mutable companion
class idiom (the purpose is to ensure Integer and
MutableInteger both have the same add() method).

public abstract class AbstractInteger {
    public abstract AbstractInteger create(final int value);
    public abstract int getValue();
    public AbstractInteger
                         add(final AbstractInteger value) {
        return create( getValue() + value.getValue() );
    }
}

public class Integer extends AbstractInteger implements
  ToMutable {
    int value;
    public Integer(final int value) { this.value = value; }
    public AbstractInteger create(final int value) {
        return new Integer(value);
    }
    public int getValue() { return value; }
    public MutableInteger toMutable() {
        return new MutableInteger(value);
    }
}

public class MutableInteger extends AbstractInteger
implements ToImmutable {
    int value;
    public MutableInteger(final int value) {
        this.value = value;
    }
    public AbstractInteger create(final int value) {
        return new MutableInteger(value);
    }
    public int getValue() { return value; }
    public Integer toImmutable() {
        return new Integer(value);
    }
    public void setAdd(final AbstractInteger value) {
        this.value += value.getValue();
    }
}

Integer's add() method arguments are two AbstractIntegers
and it returns an AbstractInteger, therefore this is three
boxing operations on the call immutable.add(immutable) if
immutable is a java.lang.immutable.Integer. All this boxing
could make add() slow and therefore for performance reasons
some operators may be coded directly in Integer as well as
in AbstractInteger.

The extra linguistic feature of a marker interface,
Immutable, gives backward compatibility (no new keyword)
and allows:

if (immutable instanceof Immutable) ...


This bug can be reproduced always.

CUSTOMER WORKAROUND :
Hand code an Immutable  customer :
1. Make class final
2. Make all fields final
3. Make all mutable fields private
4. Write hashCode() and equals() or control creation (see K
   below)
5. Don't inherit from an  customer  that has non-static fields
6. Defensively copy mutable constructor arguments
7. Defensively copy mutable fields returned from methods

Disadvantages:
A. Not compiler enforced
B. Can't test for immutability
C. JVM can't eliminate pointers for small objects
D. JVM can't aggregate into arrays
E. JVM can't stack allocate
F. JVM can't assume same  customer  between JVMs (distributed
   app.)
G. JVM can't assume same  customer  between invocations
H. Compiler can't enforce initialisation (instance could be
   null)
I. == isn't necessarily the same as equals() and isn't
   mapped to equals()
J. Defensive copying is tricky, see "Effective Java" Item 24
K. Instead of writing equals() and hashCode() and to ensure
   that ==, hashCode(), and equals() mean the same (see I
   above),  customer  creation could be controlled so that
   identical objects are not multiply created (hash-
   consing). Unfortunately this can be a performance
   problem and is tricky to do in a manner that still
   allows garbage collection ("Effective Java", Item 4,
   page 16, and Item 5).
L. Easy to accidentally circumvent with serialization
M. Little support in current libraries
(Review ID: 137637) 
======================================================================
Work Around
N/A
Evaluation
We are seriously considering this issue, and have similar (though not 
identical) proposals under review. I can't say whether this or anything
like it will get into the language.

  xxxxx@xxxxx   2001-12-21
Comments
  
  Include a link with my name & email   

Submitted On 24-JAN-2002
davidtribble
The problem with using an 'Immutable' marker interface
is that it really doesn't solve the problem that a true
'const' keyword would.

For example, we want to provide an Employee class that
contains a Date object encoding the date of hire, among
other attributes:

    public class Employee
    {
        Date        m_hire;     // (A)
        ...
    }

We would also like to have getter method to establish
the hire date for a given employee:

    // First attempt
    public void setHireDate(Date d)
    {
        m_hire = d;         // (B)
    }

The problem with the code above is that the 'm_hire'
member refers to a mutable Date object, which could be
modified by other methods outside the class.  It would
be desirable to recode it like this:

    // Second and better attempt
    public void setHireDate(const Date d)
    {
        m_hire = new Date(d);   // (C)
    }

The new code makes a copy of the Date object, so that
no outside influence can modify it.

We would also like to provide a getter method to
retrieve the hire date:

    // First attempt
    public Date getHireDate()
    {
        return (m_hire);        // (D)
    }

The problem with the code above is that the 'm_hire'
member is returned to the caller, which can now quite
easily modify its contents.  This makes useless all of
our previous efforts to keep the Date object private
and unaffected by outside influences.  One way to
prevent our private Date object from being modified is
to return a copy, which the caller can then modify to
his heart's desire:

    // Second attempt
    public Date getHireDate()
    {
        return (new Date(m_hire));  // (E)
    }

While this protects our private 'm_hire' member from
undesired modifications, it does so at the cost of
creating an entire new Date object.  If we use this
technique for very large or complex members, this could
become quite expensive in terms of memory and time.  A
better approach is to rewrite the getter method so it
returns a Date object that can't be modified at all:

    // Third and better attempt
    public const Date getHireDate()
    {
        return (m_hire);        // (F)
    }

Now we can simply return a reference to our private
Date object, while insuring that it won't (can't) be
modified by any methods outside our class.

The complete class code now looks like this:

    public class Employee
    {
        Date        m_hire;         // (A)
        ...

        public void setHireDate(const Date d)
        {
            m_hire = new Date(d);   // (C)
        }

        public const Date getHireDate()
        {
            return (m_hire);        // (F)
        }

        ...
    }

Continued...


Submitted On 24-JAN-2002
davidtribble
Continued...

In contrast, we can't do such a thing near as easily
using an 'Immutable' marker interface class.  One
reason is that an Immutable class provides immutability
(or constness) at the class level instead of at the
object level.  This means that our 'm_hire' member
can't simply have type 'Date', but must be declared as
having a type which we must create that both extends
'Date' and implements 'Immutable':

    private class OurDate   // (1)
        extends Date
        implements Immutable
    {
        OurDate(Date d)
        {
            super(d);
        }
    }

    public class Employee2
    {
        OurDate     m_hire;     // (2)
        ...
    }

Our setter method is fairly simple:

    public void setHireDate(Date d)
    {
        m_hire = new OurDate(d);    // (3)
    }

But our getter method suffers from the same problem as
we had at (C), that we must somehow make a publicly
accessible Date object from a privately inaccessible
ConstDate object:

    public Date getHireDate()
    {
        return (new Date(m_hire));  // (4)
    }

Getting this to work might require adding a conversion
method to the OurDate class.

The alternative is not any prettier, since it must
expose our immutable ConstDate class to the outside
world:

    // Second attempt
    public OurDate getHireDate()
    {
        return (m_hire);    // (5)
    }

For this to work properly, we will have to override the
methods of Date in our ConstDate class which allow its
contents to be modified.  Of course, if we want to
modify the contents within our package, we must also
provide package accessible setter methods as well:

    public class OurDate        // (6)
        extends Date
        implements Immutable
    {
        OurDate(Date d)
        {
            super(d);
        }

        public void setTime(long t)     // (7)
        {
            // Overrides super.setTime()
            throw (new Error("Not supported"));
        }

        void modifyTime(long t)         // (8)
        {
            super.setTime(t);
        }

        ...
    }

What a mess.  It's so much simpler when we have 'const'.

See the 'const' proposal, RFE 4211070, at
<http://developer.java.sun.com/developer/bugParade/bugs/4211070.html>


Submitted On 24-JAN-2002
hlovatt
davidtribble, thanks for your reply. One point concerning my
proposal that I need to clarify; you can't arbitrarily add
"implements Immutable" to make a class immutable. For a
class to be immutable it can only extend from class
hierarchies that don't define any non-static fields and the
class itself can only have Immutable or primitive fields.
These are necessary conditions so that the compiler can
enforce immutability (constness) without adding runtime
checks or conservatively copying all returns. Therefore
there would be no way to use Date, for example, in an
immutable type.

The compiler can't enforce immutability with your const
proposal unlike my immutable proposal, the problem with your
const proposal is generally referred to as const aliasing in
the C++ world. You give the example of returning a const
Date; but the compiler (without runtime checks) can't
enforce that the Date isn't changed! Consider:

public class Employee {
    Date hire;
    void set(Date hire) { this.hire = new Date(hire); }
    const Date supposedlyConstGet() { return hire; }
    public static void main(String[] args) {
        Employee e = new Employee();
        e.set( new Date(1) );
        const Date notConst = e.supposedlyConstGet();
        e.set( new Date(2) ); // Oops notConst changed!
}

There is no way round this problem without extra runtime
checks or copying, hence it is necessary to ban mutable
types completely from immutable classes if you want them
fast. I gave another example of this const aliasing written
in C++ in the 'add const RFE' (4211070).


Submitted On 03-FEB-2002
hlovatt
Hi, I made a number of mistakes in the code I posted 
above - late at night! The correct code is below, I have 
commented out const so that it can be compiled and run.

import java.util.Date;
public class ConstAliasing {
    Date date = new Date();
    void set(Date date) { 
        this.date.setTime( date.getTime() );
    }
    /*const*/ Date supposedlyConstGet() { return date; }
    public static void main(String[] args) {
        ConstAliasing ca = new ConstAliasing();
        ca.set( new Date(1000) );
        /*const*/ Date notConst = ca.supposedlyConstGet();
        System.out.println(notConst);
        ca.set( new Date(2000) ); // Oops notConst changed!
        System.out.println(notConst);
    }
}


Submitted On 09-FEB-2002
abies
cowwoc:
They have to be final to allow expanding on stack and inside
other objects. For example if jvm want to expand
ImmutableData inside some other class, it has to allocate
certain amount of place. It could be an unpleasant suprise
if later some subclass of ImmutableData would be assigned
there, with many more fields. 

Converting from/to immutability would allocate new objects.
Problem with C++ is that you get non-const view of the
_same_ object. Here you will get different object, not
aliased with previous one, just with same data copied on
very start. I still hardly see a use for it, but I think
this was a reason behind this part.


Submitted On 09-FEB-2002
hlovatt
Hi,

Abies is correct in all he/she said re. Cowwoc's comments. 
I would also add that you can't write an equals method for 
derived types (see 'Effective Java' Item 7). I will also 
reiterate Abies's point that the call toMutable() allocates 
a new object and therefore the const alias problem seen in 
C++ doesn't occur. 

The reason for providing this mutable/immutable facility is 
for large objects that take some time to allocate, I was 
particularly thinking of matrices, you can get a 
performance improvement by overwriting the old object 
instead of allocating a new one. This is much like String 
(immutable) and StringBuffer (mutable) do today. If you 
write:

s + s1 + s2

Where s, s1, and s2 are java.lang.String the compiler 
actually generates:

new StringBuffer(s).append(s1).append(s2).toString()

Using this new proposal the equivalent, i.e. if s, s1, and 
s2 are java.lang.immutable.String (the proposed new String 
class), would be:

s.toMutable().append(s1).append(s2).toImmutable()


Submitted On 09-FEB-2002
cowwoc
Hi,

Please clarify the following two issues:

1) I don't see why immutable classes need be final. What's
wrong with allowing them to be extended?

2) I don't like the idea of converting from/to immutability.
Personally I believe one of the biggest problem with the
'const' identifier in C++ is that it isn't _really_
enforced. Users can easily use the "const_cast" to modify
"constant" variables. This shouldn't be allowed. If
something is constant, I don't forsee any situation why you
were ever _have_ to convert it to non-constant in its
lifetime. Am I missing some basic design issue here? Please
clarify..


Submitted On 11-FEB-2002
Ixchel
I've said before that I support the concept of adding 
immutable types to Java. However, I do NOT think that this 
is in any sense a replacement for the 'const' keyword. 
Quite simply, immutability (a const object) and constness 
(a const reference to a possibly non-const object) are two 
different things, with completely different intents and 
uses. Comparing the two as if one could replace the other 
is just not reasonable. They are completely orthogonal 
concepts. I do not think in any sense that having immutable 
objects would remove the need for a way to document and 
preserve constness of references, however.

With that said, I do support some kind of immutability in 
Java. However, I am uncomfortable with the idea of using an 
interface to indicate it instead of some kind of special 
keyword (e.g. "immutable" and "isimmutable"). Unlike 
Serializable, the semantics for the Immutable interface as 
described would impact how (and if) legal Java source code 
could be compiled. This would create a version skew of Java 
compilers just as large as the one that would be created by 
adding new keywords.
Also, I don't think immutable classes should be forced to 
be 'final'. Extending an immutable class is a perfectly 
reasonable thing to do. Yes, certain compiler optimizations 
(pass-by-value) may not be able to be used for non-final 
immutable objects, but this may be perfectly fine in many 
cases. There is no need to REQUIRE immutable objects to be 
final.
Also, it is quite common to have both an immutable object 
and a non-immutable object share the same interface 
(containing only accessor methods), so that a reference to 
that interface can be passed around without knowing which 
it refers to. This does not seem possible in the current 
proposal. In fact, it does not seem possible to declare an 
interface 'immutable' at all under the current proposal. 
This is a problem.


Submitted On 11-FEB-2002
andythomascramer
While immutable types would be appreciated, they are not a 
replacement for const-restricted references. The two are 
orthogonal concepts.

Hlovatt's defense against davidtribble's illustration is 
flawed by a lack of understanding of both existing Java and 
the proposal for const-restricted references. Consider:

>        /*const*/ Date notConst = ca.supposedlyConstGet();
>        ca.set( new Date(2000) ); // Oops notConst changed!
        
  Hlovatt is incorrect. The second line does not change 
notConst. The variable notConst is a pointer, whose value 
is not changed by the second statement. Java does not offer 
object variables. 

Hlovatt's criticism of const-restricted references depend 
on a presumption that they're intended to make an object 
immutable. They're not. They're only intended to restrict 
certain references to const operations.

My dessert topping doesn't offer immutable behavior either. 
Perhaps this RFE should be an alternative to it as well.



Submitted On 11-FEB-2002
dkf
Problems as I see them:
  1) The thing which it would be very nice to have would be
immutable/const arrays (i.e. where you can't assign to any
of the members after creation.)  The proposal does not give
that.
  2) When people say an immutable/const object, do they
really mean that?  Or do they actually just refer to the
view of the object?  Immutability is a property of the
object itself, and constness is a property of the view of
the object (which is effectively the reference to the object
in Java.)  It is conceivable that access through a const
reference might cause update to the internal state of the
object (e.g. uses an internal pool of objects, or a count of
the number of times a method has been called.)
  3) Immutability has *nothing at all* to do with object
identity.  Do not confuse them!  Equality of objects is
defined by equals() (and, by implication, hashCode()) and
identity of objects is defined by == (and, by implication,
System.defaultHashCode()).  Immutability of objects is
defined by whether they change between one look at them and
another, and in general might only be true over a restricted
timespan or through some particular set of views.
  4) I might expect a compiler to perform subexpression
elimination on methods called from a const reference.

If I thought really hard, I might even be able to bring
these points together in a coherent whole; but I've never
done my best thinking on a Monday, so this is what you're
getting instead...  :^)


Submitted On 13-FEB-2002
hlovatt
Thanks for all your postings, various topics have been 
covered. Forgive me if I don't do all the issues raised 
justice. I am conscious of the length of this post, this 
post is virtually a FAQ for the proposal already!

Typical usage
=============
I imagine that if the proposal was accepted then people 
would start of writting immutable classes and using them in 
a style similar to that used in functional programming. 
Where you create objects and throw them away with great 
regularity. Despite the heroic efforts of the people who 
write JVMs this can still cause a problem because it can 
lead to lots of short lifetime objects.

Taking the example of an Integer class, which I am am 
actually proposing to be part of a new package of classes 
called java.lang.immutable, it is intended that these new 
classes replace the current classes like java.lang.Integer 
and java.lang.String.

But for the moment lets suppose that we are writting our 
own Integer, we might first write:

public class Integer impliment Immutable {
    int value;
    public Integer(final int value) { this.value = value; }
    public Integer add(final Integer value) {
        return new Integer( value + value.value );
    }
}

After some profiling we might find that too many 
temporaries are created because we are using add a lot. 
This code would be re-worked to give a companion mutable 
class to prevent the creation of temporaries.

public abstract class AbstractInteger {
    public abstract AbstractInteger create(final int value);
    public abstract int getValue();
    public AbstractInteger
                         add(final AbstractInteger value) {
        return create( getValue() + value.getValue() );
    }
}

public class Integer extends AbstractInteger implements
ToMutable {
    int value;
    public Integer(final int value) { this.value = value; }
    public AbstractInteger create(final int value) {
        return new Integer(value);
    }
    public int getValue() { return value; }
    public MutableInteger toMutable() {
        return new MutableInteger(value);
    }
}

public class MutableInteger extends AbstractInteger
implements ToImmutable {
    int value;
    public MutableInteger(final int value) {
        this.value = value;
    }
    public AbstractInteger create(final int value) {
        return new MutableInteger(value);
    }
    public int getValue() { return value; }
    public Integer toImmutable() {
        return new Integer(value);
    }
    public void setAdd(final AbstractInteger value) {
        this.value += value.getValue();
    }
}

Then instead of writting:

Integer i = new Integer(1);
Integer j = i.add(1).add(2).add(3).add(4);

you can write

Integer j = i.toMutable().setAdd(1).setAdd(2)
                         .setAdd(3).setAdd(4).toImmutable();

which saves on the creation of temporary objects. This is 
very similar to how strings are currently concatonated in 
Java using a StringBuffer.


Submitted On 13-FEB-2002
hwc
I like this proposal.  I’d like to be able to create an 
array of immutable objects, for example, without the 
overhead of allocating each object on the stack and copying 
them each time, but…

1) I’m not sure how your == deals with null.  Supposing, 
for example, that I wanted to initialise a static variable 
the first time I used it, I might say:

static SomeType constantData;
if( contantData == null )
	constantData = readFromDatabase();

Is this a compile-time or run-time error?  Either way it 
breaks a useful idiom.  Primitive types always store a 
value; object references don’t.  This makes optimisation 
more difficult, too.

2) I’d rather the compiler complained if I hadn’t followed 
your rules - making everything final and so on, instead of 
doing it for me.  The meaning of a piece of code should be 
evident to the reader, not dependent on its context.  I 
suspect this would give greater backwards compatibility, 
too.

3) A similar effect could be achieved by marking a class 
const but const has a finer level of granularity – 
individual methods and object references could also be 
marked const.

What seems to be at issue is a question of idiom: should 
mutable and immutable objects be different, even if they 
appear to share a common interface (e.g. String and 
StringBuffer), or should you be able to restrict the 
interface to existing objects, making them appear immutable 
to the user.


Submitted On 13-FEB-2002
hlovatt
Const view isn't the same as immutable
======================================
A const view of an object isn't the same as an immutable 
object, but they are used in many overlapping 
circumstances. For example in the const view RFE people are 
continually saying that what they want is a const array 
(also see array section below), they mean an array of int, 
say, where you can't change the values in the array. This 
usage is covered by both a const view and immutable. I 
would argue that people nearly always want immutable, not a 
const view, even if they say const (see below). For example 
in davidtribble's post he contrasts, as many people do, 
const with conservatively copying returned values. He 
clearly can't mean a const view, because if you change the 
original the returned copy isn't changed. He is using const 
to give some form of seperation (elimination of side 
effects) between the returned object and the original. I 
think this is one of the most common usages for const in 
C++ and is better handelled with an immutable object.

Much of this confusion about what people mean when they say 
const is caused because const is a poor term for const 
view, readonly would be much better - as  people have said 
in the const veiw RFE. I used Immutable to avoid the word 
const or constant because of this confusion.

However you can argue that being able to change an object 
and have a const view of the object is a useful feature. It 
is not incompatible with my immutable proposal, the 
proposed package, java.lang.immutable, could be extended to 
include const view versions of each set of classes, e.g. 
using the Integer example given above the original 
MutableInteger could be broken into two classes, 
ConstInteger and a new MutableInteger, as below:

public class ConstInteger extends AbstractInteger {
    protected int value;
    public ConstInteger(final int value) {
        this.value = value;
    }
    public AbstractInteger create(final int value) {
        return new ConstInteger(value);
    }
    public int getValue() { return value; }
}

public class MutableInteger extends ConstInteger
implements ToImmutable {
    public MutableInteger(final int value) { super(value); }
    public AbstractInteger create(final int value) {
        return new MutableInteger(value);
    }
    public Integer toImmutable() {
        return new Integer(value);
    }
    public void setAdd(final AbstractInteger value) {
        this.value += value.getValue();
    }
}

Therefore we have an immutable 'Integer', const 
view 'ConstInteger', and mutable 'MutableInteger'. They all 
interoperate via the common base class 'AbstractInteger'.

I think that the fine distinction between Integer and 
ConstInteger isn't necessary, people will use Integer 
because they want immutability and all the benefits that go 
along with it like: its value can't be changed, elimination 
of pointers, speed, compiler written cloning, etc. Hence I 
didn't suggest ConstInteger. If you really need 
ConstInteger you can easily write your own.

Another reason for not providing ConstInteger is that its 
usage overlaps with the toMutable/toImmutable idiom 
explained above.


Submitted On 13-FEB-2002
hlovatt
Non-final immutable values
==========================
My argument for not providing these is much the same as for 
not providing ConstInteger, you loose many of the benefits 
like its value is no longer constant (see below) pointer 
elimination, and speed. Also you can easily write your own 
if you need it:

public class ExtendableInteger extends AbstractInteger {
    private final int value;
    public ExtendableInteger(final int value) {
        this.value = value;
    }
    public AbstractInteger create(final int value) {
        return new ExtendableInteger(value);
    }
    public int getValue() { return value; }
}

If you then extend ExtendableInteger with a class that has 
a field that can change, then this new class clearly isn't 
immutable. But the new mutable class can be used in place 
of ExtendableInteger, which is Immutable. I don't like this 
ability to be able to substitute something that is not 
immutable for a type that I intend to be immutable, hence I 
always make my immutable types 'final' when I write them 
currently in Java. Mutable derived types wasn't the primary 
reason I made the proposed immutable type final, it was for 
ensuring that people didn't forget the final keyword and by 
forgetting it forgo the performance advantages.

Hence I thought that the default for Immutable should be 
final, but it is possible to write a clever compiler that 
behaves differently if the Immutable class is final or not. 
Also see section Aside below.

Support for immutable arrays
============================
I have added support for immutable arrays in the proposal 
in two forms. 

1. You can write 'SomeImmutableType[] x', e.g. 'Integer[] 
x' and the JVM can eliminate all the pointers etc. so that 
the example is an immutable form of 'int[] x'.

2. Also I have added a convenience class Array that is 
used 'Array<Integer> x' (I assumed Generic types are in). 
Array is immutable itself and therefore forms the basis of 
immutable multi-dimensional arrays, 
e.g. 'Array<Array<Integer>> x'. I would hope that in time 
the syntax Array<Integer> would replace Integer[].

Keyword
=======
It is possible to infer immutability using a keyword 
instead of a marker interface, James Gosling, no less, has 
suggested this. I preferred the marker interface because:

1. It doesn't need a keyword and hence won't beak old code 
that used the new keyword as a variable name.

2. You can write 'x instanceof Immutable'.

3. RTTI doesn't require changing.

4. It fits in logically, you can say ''a variable of type 
Immutable'' and people know you mean some class that 
impliments Immutable.



Submitted On 13-FEB-2002
hlovatt
Immutable interfaces
====================
The proposal allows an interface to extend Immutable and 
therefore mark another interface as immutable. For example 
part of the proposal is the interface ToMutable that 
extends Immutable.

Coding for either Immutable or Mutable forms
============================================
The proposal supports programming to an immutable 
interface, see above, and also to class hierarchies that 
don't define non-static fields. For example you can declare 
something to be AbstractInteger and use either Integer or 
MutableInteger.

Identity
========
In general in Java you want == and equals to distinguish 
between objects, but for an immutable object you only want 
equals. For an immutable object the JVM is quite entitled 
to eliminate the pointer completely. Therefore == has no 
meaning, in its conventional Java sense, hence it is mapped 
to equals.

Notnull
=======
Because the JVM can eliminate the pointer to an immutable 
object a variable of type Immutable cannot be assigned the 
value null. This is a useful feature that can be used to 
save all that 'if (x == null) throw ...'.

Optimization
============
Any optimizations the compiler or the JVM can do for a 
const view of an object it can do for an immutable object. 
Vice versa isn't true, there is much more that can be done 
with an immutable object.

Aside
=====
I didn't put this in my proposal because I thought people 
would complain too much ;). I would prefer an immutable 
declaration to infer finality. As the proposal stands you 
can write:

Integer i = new Integer(1);
i = new Integer(2);

I think this is confusing, when you say something is 
immutable you generally really mean it. You don't mean 
under some circumstances it is immutable. Therefore you 
will nearly always mean:

final Integer i = new Integer(1);

even if you write:

Integer i = new Integer(1);

Therefore I would also like to have added into the proposal 
that immutable type declarations were by default final, 
however I thought people would think I was mutating [sic] 
the language.


Submitted On 13-FEB-2002
finking
Regarding immutable arrays, suggestion 1 by hvolatt is not 
sufficient.

   Integer[] intArray = { new Integer(0), new Integer(1) };

is not an immutable array. It prevents intArray from being 
reassigned like this:

    intArray = blah; // error

and it prevents any of it's members being changed like this:

   intArray[0].modifier(); // error

but it does not prevent any of its elements being 
reassigned:

   intArray[0] = new Integer(9); // OK

The second solution works (as far as I can see), but has
totally different syntax to normal arrays, which is not
what you want. Finally, even if solution 1 did work note
that it still forces you to jump through hoops if you want
an immutable array of primitive types; you have to put them
inside objects first. Why all the complication? What's
wrong with using the const keyword? It is already a reserved
word in Java after all.

Regarding this RFE in general, others have already captured 
my thoughts, here are some excerpts that sumarise them:

>...I don't think immutable classes should be forced to 
>be 'final'. Extending an immutable class is a perfectly 
>reasonable thing to do. Yes, certain compiler 
>optimizations 
>(pass-by-value) may not be able to be used for non-final 
>immutable objects, but this may be perfectly fine in many 
>cases. There is no need to REQUIRE immutable objects to be 
>final...
Moreover there is no reason why the compiler can't 
establish whether a particular class is final and optimise 
it (or not) accordingly. The inlining optimisation that the 
hotspot compiler does already does similar checking.

Finally, the crux of the matter:
>...I do support some kind of immutability in 
>Java. However, I am uncomfortable with the idea of using 
>an interface to indicate it...

Regards





Submitted On 14-FEB-2002
hlovatt
3. Should immutability be per class or per object?
==================================================
This is probably the question that is most contriversial 
and seems to be at the route of assertions that this 
proposal, immutability, doesn't have anything in common 
with the C++ style const proposal. Whereas I see a good 
deal of overlap between the two. I thought about per object 
declarations when I made the proposal and I will briefly 
outline my thoughts below.

But first I will digress onto a philisophical point. My 
main feeling on this is that you always have to design your 
class to use immutability or similar. EG in C++ if you 
don't use const in any method argument declaration and 
don't use const as a modifier to any method signature then 
althogh someone can declare an object as const, they can't 
do anything with it! Therefore I actually see very little 
difference between the two approaches, you always have to 
design your class to use immutability even if the syntax 
implies it is on a per object basis.

I think the question of immutability on a per object basis 
has three parts: A. is it practical, B. what syntax is 
suitable, and C. is it desirable?

A. Is it practical?
-------------------
Yes it is practical (I think!). The compiler could  
automatically split a class into Abstract$Integer, 
$Integer, and Mutable$Integer say (I have put dollars in 
because they are compiler generated and used the 
terminology I chose for this proosal). Then at the object 
level the user could choose which version they required. 
This is really just asking the compiler to automatically 
follow the idiom outlined in this proposal or similar (see 
below under syntax). This is similar to what the compiler 
does for inner classes currently.

B. What syntax?
---------------
The syntax is a tricky question, certainly the C++ syntax 
isn't very good. It is difficult to think up something OK, 
see all the discussions in the C++ style const proposal. I 
went off the idea of a per object basis, partially because 
of the syntax question. Below I have outlined my version of 
the syntax, but because I never thought through per object 
immutability fully there could be errors in this syntax.

The syntax needs keywords or symbols (I can't think of a 
way to use a marker interface), I will use keywords below. 
The declaration of an object (field, local, or argument) 
could become.

Integer eitherImmutableOrMutable;
immutable Integer immutableOnly = new immutable Integer(1);
mutable Integer mutableOnly;

and for arrays

Array<Integer> eitherImmutableOrMutable;
immutable Array<immutable Integer> immutableOnly = ...;
mutable Array<mutable Integer> mutableOnly;
immutable Array<mutable Integer> error; // Error

i.e. Integer maps to Abstract$Integer,   immutable Integer 
to $Integer, and mutable Integer to Mutable$Integer.


Submitted On 14-FEB-2002
hlovatt
The declaration of methods is trickier, my thoughts were 
that if no fields or methods are declared immutable or 
mutable then the compiler behaves as it currently does 
(except that returns, see below, could optionally be used). 
But if any fields or methods are immutable or mutable then 
new declaration syntax for methods is used. IE:

[modifiers] <name>(...) returns ... throws ... {...}

in particular, the return type is moved to after the method 
name and is introduced by the new keyword returns. Moving 
the return type nicely distinguishes an immutable method 
from one that returns an immutable type and keeps a Java 
like modifier list at the front of the declaration. The 
modifiers list is extended to include immutable and mutable.

Methods declared immutable only have access to fields 
declared immutable, like static. Methods declared mutable 
have access to all fields, again like static. Methods not 
declared either immutable or mutable behave like mutable 
methods.

For example the Integer class is given below. Note the 
compiler supplies toMutable() and toImmutable() as well as 
cloning, final fields, etc. for the immutable form $Integer.

public class Integer {
    private immutable int value;
    public Integer(final int value) { this.value = value; }
    public immutable add(final int value) returns Integer {
        return new Integer(this.value + value);
    }
    public mutable setAdd(final int value) returns void {
        this.value += value;
    }
}

After compilation the resulting classes Abstract$Integer, 
$Integer, and Mutable$Integer are as described in this 
proposal (but they don't use $ in their names in this 
proposal).

C. Is it desirable?
-------------------
Many people would say yes. I came down on the side of it 
was too big a change and the simplier alternative as 
proposed does everything the more complicated option of a 
per object basis does and therefore go with the simpler 
alternative. I guess that like 2, above, it is best to go 
with the majority.


Submitted On 14-FEB-2002
hlovatt
Reply to Hwc - thanks for saying you like the proposal :)

1. Lazy initialization idiom
============================
Changing your example to use the Integer class spelt out 
above, because the code is spelt out (your data base 
example is more realistic):

class X {
    static Integer constantData;
    public final static Integer get() {
        if ( contantData == null )
            constantData = new Integer(1);
        return constantData;
    }
}
	
Would be two compile time errors: 1 because constantData 
wasn't initialized and 2 because constantData is compared 
to null.

The way to program this is:

static AbstractInteger constantData;

and

if ( contantData == null )
    constantData = new Integer(1);
	
An AbstractInteger can be null, so this works. But the 
compiler/JVM can do less optimization, it can no longer 
eliminate the pointer, but your data is still immutable. An 
alternative that retains the optimizations is the 
initialize on demand, holder, class idiom:

Class X {
    private static class Holder {
        static final Integer i = new Integer(1);
    }
    public final static Integer get() { return Holder.i; }
}

See ''Effective Java'', Item 48 (this also works in 
multithreaded programs, unlike lazy initialization).

2. Compiler shouldn't insert final etc.
=======================================
Difficult to know what it is best to do, I err on the side 
of getting the compiler to do more because people tend not 
to put things in if they are optional (and in this case 
they would loose optimization) and get annoyed if they have 
to put something in always (why doesn't the compiler do 
this - it knows it is needed). I look on this a bit like 
not needing to use public in interface definitions. 
Ultimately it isn't that important and we should go with 
the majority.


Submitted On 14-FEB-2002
hlovatt
Reply to finking - thanks for your support :)

1. Integer[] x isn't constant
=============================
Good point - I missed this!

2. Array<Integer> syntax
========================
It is different, but I like the syntax. Remember that we 
will soon, post generics, be writting:

List<Integer> x;
Map<Integer> x;
etc.

I imagine Array to inherite from Collection or List and then

for (final Iterator<Integer> i = x.iterator(); i.hasNext
(); ) {
     Integer integer = i.next();
     ...
}

will work for Lists, Maps, SortedSets, and Arrays.

3. Automatically final, marker interface
========================================
Not important - go with the majority.


Submitted On 23-FEB-2002
hlovatt
In a previous post I said that a const view of an object 
could be added to the object hierarchy. I missed that the 
abstract class in the proposed hierarchy, AbstractInteger 
for example, already provides this functionality. So const 
views are part of the proposal!

The next two points are in reply to suggestions by finking.


Non-final immutable classes
===========================

The abstract classes also provide the basis for 
inheritance, since you can't inherit from the immutable 
classes. I.E. if you want to extend the immutable integer 
class, Integer, you can't; but you can extend 
AbstractInteger which gives the same functionality, well 
almost. As proposed AbstractInteger doesn't implement 
ToMutual, so I propose that it does and to enable this 
ToMutual no longer extends Immutable.

Annoying to have to wrap primitives
===================================

As the proposal stands you have to wrap a primitive in an 
immutable before an immutable array can be used (note there 
is no speed or memory penalty as there currently is with 
the Integer etc. wrappers). In most circumstances this will 
be painless, e.g.:

Array<Integer> ai = new Array<Integer>(new int[] {1, 2});

In other circumstances, particularly when using 
MutableArray, you will manually have to do this, e.g.:

MutableArray<Integer> mai = new MutableArray<Integer>(2);
int x = calculateX();
int y = calculateY();
mai.set( 0, new Integer(x) );
mai.set( 1, new Integer(y) );
Array<Integer> ai = mai.toImmutable();

However it is proposed that the new Integer type etc., 
unlike the existing Integer type etc., have a full set of 
operators and since they are immutable they will be of 
similar speed to primitive types and take up no more 
memory, therefore instead of calculateX using and returning 
a primitive it could be written using Integer. Therefore 
the example above becomes:

MutableArray<Integer> mai = new MutableArray<Integer>(2);
mai.set( 0, calculateX() );
mai.set( 1, calculateY() );
Array<Integer> ai = mai.toImmutable();


Submitted On 19-MAR-2002
hlovatt
Below is a summary of changes to the original suggestion in 
light of comments made in this forum and my further 
thoughts. In the description below I have used the terms 
XXX, AbstractXXX, and MutableXXX where XXX is the name of 
the immutable type, e.g. Integer.

1. The interface ToMutable does not impliment Immutable

2. The AbstractXXX form of a class impliments ToMutable

The above changes make the AbstractXXX and XXX types have 
identical interfaces, therefore AbstractXXX can be used as 
a base class to extend from (you can't extend XXX because 
it is final). The AbstractXXX form also provides a read-
only (const) view to a MutableXXX object.

3. Arrays of types that impliment Immutable are themselves 
   Immutable

Thus 'integerArray[0] = new Integer(1);' is an error.

4. A declaration of an immutable object is automatically 
   final

Thus 'integerObject = new Integer(1);' is an error.

5. The proposed new package java.lang.immutable should 
   contain:

  Interfaces:         Immutable, ToMutable, and ToImmutable
        
  Byte classes:       AbstractByte and Byte
  Short classes:      AbstractShort and Short
  Integer classes:    AbstractInteger and Integer
  Long classes:       AbstractLong and Long
  BigInteger classes: AbstractBigInteger, BigInteger, and
                      MutableBigInterger
                            
  Float classes:      AbstractFloat and Float
  Double classes:     AbstractDouble and Double
  BigDecimal classes: AbstractBigDecimal, BigDecimal, and
                      MutableBigDecimal
       
  Character classes:  AbstractCharacter and Character
  String classes:     AbstractString, String, and 
                      MutableString
        
  Array classes:      AbstractArray, Array, and 
                      MutableArray
        
The original proposal had MutableXXX for the equivalent of 
the primitive types, this isn't necessary as the only point 
in the MutableXXX forms is as a speed optimization when the 
creation of a new object is slow. It is unlikely that the 
primative equivalent types will be slow to create, 
therefore don't bother with MutableXXX forms of these small 
classes.

The original proposal didn't include the BigInteger and 
BigDecimal classes from java.math.


Submitted On 21-MAR-2002
hwc
Is it possible to simplify the suggested heirarchy 
further?  Taking this proposal together with the work being 
done on XML-RPC, there is a danger that we’ll end up with 
far too many classes for most people to understand the 
differences.

Taking integers for example, we seem to need four classes: 
an abstract base class and three descendants, one immutable 
and not nullable, one mutable and nullable, one immutable 
and nullable (i.e. java.lang.Integer).

This leads me to ask two questions:

1) Why not graft the new classes into java.lang?  This 
would allow the standard Integer to extend AbstractInteger 
which could itself extend Number.

2)	How important is the re-definition of ==?  This 
seems to be the essential difference between 
java.immutable.Integer and java.lang.Integer.  I can see 
why its useful to hide the identity of immutable objects 
but, in practice, might it be better not to rather than 
create extra classes?  What if == always returned false for 
immutable objects?


Submitted On 01-APR-2002
hlovatt
Sorry for not replying sooner, this forum seems to have had
a problem where you could not make a post.

Reply to hwc post point 1
=========================

You are suggesting reducing the number of classes in the 
proposed API, I think this is a good thing. You suggest 
eliminating java.lang.Integer, I think this is a good idea. 
If we had java.lang.immutable.Integer you wouldn't need 
java.lang.Integer (particularly if its interface was 
compatible in the manner you suggested). One option is to 
simple depreciate it, this is what I had in mind.

Your suggestion is that we put the immutable classes into 
java.lang, presumably the new immutable Integer is then 
called something like ImmutableInteger to distinguish it 
from the existing Integer. I would like to use the name 
Integer because it is shorter and putting everything into 
java.lang still leaves just as many classes, although a 
package isn't eliminated. So to me this idea isn't ideal 
and I will make a different suggestion.

Another idea is that rather than introduce a new package we 
could set a bit in the class file to indicate that the new 
java.lang package should be used rather than the old 
package. The new java.lang package contains the new 
Immutable implementing Integer and the old Integer is no 
longer present. A compiler savvy to immutable could have a 
compile time switch to allow it to work with the old non-
immutable java.lang package. What do you think, a good idea?

That leaves AbstractInteger and Integer (I have already 
suggested eliminating MutableInteger). AbstractInteger is 
there to allow extensions because you can't extend from an 
immutable type (an immutable type must take up a fixed size 
in memory). Is there another way of allowing extensions 
without having AbstractInteger a public class or Interface?

Reply to hwc post point 2
=========================

> How important is the re-definition of ==?  

Not very in the scheme of things, this could easily be 
dropped. Also it enters dangerous territory, namely 
operator overloading. You suggest == returns false, how 
about == is an error? If == is an error, code using 
immutable types won't be broken by operator overloading.


Submitted On 05-APR-2002
hwc
Thanks Hlovatt; you’ve got me thinking.

Rather than introduce too many new types, why not make 
greater use of automatic boxing?

Suppose that most of the functionality of the current 
java.lang.Integer was implemented in AbstractInteger.  
Integer would then be more like your MutableInteger (final 
but nullable, even if it didn’t have mutator functions).  
int would remain as it was.  The compiler would convert it 
to an AbstractInteger object when necessary, or casts used 
explicitly.

Immutable types could behave in the same way.  They might 
not appear to be descended from Object: == and synchronized 
methods would be illegal, but would always provide a 
toMutable() or clone() method to create an Object with the 
same value.

StringLiteral would be an Immutable type, converted to 
AbstractString when necessary.  String and StringBuffer 
would extend AbstractString.  It might be nice to deprecate 
or re-define String but I’d imagine there’s already too 
much code out there using ==.

Underlying this suggestion is the idea that Java could 
appear to have a unified type system, as proposed for Kava: 
int, float, Object and Immutable types would all extend the 
same notional super-class.  Given such a system, toImmutable
() could return any sub-type.  Boxing – toMutable() may be 
implicit; un-boxing – toImmutable() probably wouldn’t be.

Without this, I’m not sure how immutable arrays of 
immutable types could be implemented efficiently.  
A “constructor” like Array< int > a = { 1,2 3 }; might be 
OK but Array< Point > b = { new Point( 1, 2 ), new Point( 
3, 4 ) }; might create an array of references.  Assignment 
to a standard array would require a call to toMutable(), 
clone(), or even a cast, but it’s too expensive to do 
automatically.


Submitted On 07-APR-2002
hlovatt
Hwc, I agree with all your points except possibly:

{ new Point(1, 2), new Point(3, 4) } 

not going into an immutable array. I was hoping that it 
would be possible to make the compiler smart enough to do 
this, since an array of immutable is itself immutable.


Submitted On 07-APR-2002
hlovatt
Lazy Initialization
===================

The language Haskell (http://www.haskell.org/) makes 
extensive use of immutable types, most things in Haskell 
are immutable. The Haskell runtime automatically does lazy 
initialization for immutable types. IE 

Integer integer = <some expression>;

is not evaluated until integer is actually used (assuming 
Integer is an immutable type). Once the variable is used 
the first time its value is remembered and subsequently it 
is not re-evaluated. Hopefully the same will be true in 
Java if we get immutable types.


Submitted On 07-SEP-2002
YATArchivist
My thoughts...

I agree with those who think that immutable classes don't 
need to be final. The JVM can still allocate space on the 
stack for final immutables if it wants to.

Obviously, if immutables are not automatically final your point 
3, that all fields should be private, could also be dropped; 
likewise point 9, that immutables should inherit from classes 
with no instance fields.

Similarly, I don't see the need for point 5 (== to .equals).

Points 7 and 8 (compiler generating clone() and toString()) 
should IMO be rethought and reworded. WRT clone, perhaps 
the compiler should automatically make an immutable type T 
implement Cloneable<T> (assuming generics, as you also do). 
Automatic generation of toString I disagree with - where is 
the benefit? I'll almost certainly want to write my own, so I 
can order the fields as I wish and treat Collection fields etc as 
I wish.

I disagree with 11 and 12.

13 is handled automatically if you use interfaces.

What does the readResolve() of 14 do?


Submitted On 16-OCT-2002
hlovatt
cont...

11 and 12 (immutables must be initialized and can't be null)
are necessary to allow stack allocation. Not that bad in
Java you can say:

final Integer i;
if ( someCondition() ) {
    i = new Integer(1);
}
else {
    i = new Integer(0);
}

This is different than C++ when you can have problems with
reference types needing to be initialized.

13 (Mark Immutable for JVM). Yes it is already covered, I
was thinking of a bit in the class file so that it was
quick. But you are correct, this assumption that the JVM
needs this optimization may be incorrect.

14 readResolve. This isn't really necessary and should be
dropped since I now think it is impractical.

As an aside the idea was that if the compiler can optionally
stack allocate. If it chooses not to stack allocate then I
had in mind that if the object was deserialized it would use
readResolve to return a reference to an already created
object of identical value. But this is overkill!


Submitted On 16-OCT-2002
hlovatt
Reply to YATArchivist,

Sorry for not posting sooner, I had some how missed your post.

I seem to be in the minority saying that immutables should
be final (point 1), therefore this should be dropped from
the proposal.

Similarly with regard to private fields I am again in the
minority, therefore drop point 3.

As you say, if 1 and 3 are dropped then 9 (restrictions on
inheritance) can also be dropped.

Point 5 (== same as equals); most people think this is a bad
idea, so drop this.

Points 7 & 8 (clone and toString).

First clone, I didn't want the compiler to make immutables
cloneable since there is no point in cloneing an immutable.
Just copy a reference to it (or its values if the JVM has
stack allocated), e.g. "Integer i2 = i;". The point of
covering clone was to deal with the case of someone
implementing Cloneable, another option would be to make this
an error.
Second toString. I think it is necessary for a default
toString method for if the JVM stack allocates. There is no
address and therefore toString from Object will fail.


Submitted On 19-DEC-2002
M.R.Atkinson
hlovatt,

Although the following are not necessary for Immutatble
types I agree with you that they are desirable:

Array<Integer> (and Array<Array<Integer>> x for square arrays).

Arrays of Immutable types are themselves Immutable.

I am not shure that there is any advantage of using
AbstractXXX classes rather than iterfaces, as the abstract
classes cannot have state. On general principles I would
rather use interfaces Effective Java, Item 16.

You may be in a minority as regards to Immutable requiring
final, but it is a minority that includes Joshua Bloch (not
counting Allen Holub and myself), stick with your original
proposal.

I think that == mapping on to equals() is essential, as
another reason think about

Integer i = 3;
if (i == 3) { .. }

If automatic boxing of the 3 in the if statement occurs this
will evaulate false, if unboxing of the i in the if
statement occurs it will evaulate true. Now you could make a
rule, but it would be completely arbitary and difficult to
remember.


Integer x = new Integer(5);   // x is implicitly final

finally, it should be made clear that Immutable has benefits
for:

The writer of a Immutable class, it allows him to make his
intension clear and for the compiler to check it.

The user of a Immutable class, it allows her to be shure
that the class is truely immutable (see the problems with
BigInteger, in Effective Java Item 13). It allows her to
effectively reason about her code, because interactions are
less.

The client code can perform added checks, have arrays of
Immutables also Immutable and insert implit final for
variables declared to be of Immutable types.

The JVM can use pass by value for small Immutable objects if
it desires, or place Immutable objects directly into arrays
rather than having to use references.

Continued ...


Submitted On 19-DEC-2002
M.R.Atkinson
Restating my list of requirements (with better formatting
and a few bug fixes):


Immutable classes have the following characteristics:

   1.  They are "final" or contain only private constructors.

   2.  All instance variables are private final.

   3.  All instance variables are primitive types, or
       immutable or contain only final instance variables
       themselves (recursively). There is one exception to
       this, a volatile instance variable may be lazily
       constructed.

   4.  They are not allowed to start Threads in any of their
       constructors.

   5.  They are not allowed to write to any static variable
       in any of their constructors.

   6.  Immutable objects must be fully initialized in their
       constructors (except for any volatile fields).

   7.  They cannot implement Cloneable.

   8.  If they implement Serializable they must have a
       readObject() or readResolve() implementations that
       obeys the same rules as for constructors.

   9.  They cannot contain be a copy constructor.

   10. An immutable class should not extend another class
       that contains non-static fields.

   11. No non-private methods are provided that modify
       any of the instance variables.
       


Immutable classes may also be treated as lightweight
classes, as long as:

   12. toString() should be implemented, the default
       toString() in Object that gives an objects address
       is not meaningful in lightweight classes.

   13. Like primitive instance variables they are cannot be
       synchonized on.

   14. a==b maps onto a.equals(b).

   15. The equals() and hashCode() methods are
        implemented.

   16. Casting from or to an immutable class does boxing or
        unboxing.

   17. They cannot be compared to or assigned null.


The above does not specify how Immutable will be implemented
I have a slight preferrence for adding a keyword, but your
points about using a marker interface are well made.

Mike Atkinson


Submitted On 19-DEC-2002
M.R.Atkinson
No non-private methods should be able to modify the visible
state of the Immutable. Private methods may modify the state
but are only callable by constructors (or readObject()). 

The extra conditions are required to allow immutable objects
to be treated as lightweight objects being able to be passed
by value (if they are small) at the descretion of the JVM.

== should map to a.equals(b), as they both must have the
same samantics for an immutable class. Remember Immutable
objects may not be cloned or copy constructed and
implementation details like hash-consing (and pass by
reference or pass by value) should be invisible to the
programmer.

Casting to or from an Immutable will have to perform boxing
or unboxing. This allows:

Integer x = 1;

AbstractInteger y = new MutableInteger(2);
Integer z = y;

As a value type has no reference it cannot be null.


continued ...


Submitted On 19-DEC-2002
M.R.Atkinson
I have created by own list of rules for Immutable classes


Immutable classes have the following characteristics:

   1.  They are "final" or contain only private constructors.
   2.  All instance variables are private final
   3.  All instance variables are primitive types, or
immutable or contain only final
       instance variables themselves (recursively). There is
one exception to this,
       a volatile instance variable may be lazily constructed. 
   4.  Like primitive instance variables they are cannot be
synchonized on.
   5.  They are not allowed to start Threads in any of their
constructors.
   6.  They are not allowed to write to any static variable
in any of their
       constructors
   7.  Immutable objects must be initialized.
   8.  They cannot implement Cloneable.
   9.  If they implement Serializable they must have a
readObject() implementation
       that obeys the same rules as for constructors.
   10. They cannot contain be a copy constructor.
   11. An immutable class should not extend another class
(except Object) that contains
       non-static fields.
   12. No non-private methods are provided that modify any
of the instance variables.
       


Immutable classes may also be treated as lightweight
classes, as long as:

   12. a==b maps onto a.equals(b)
   13. The equals() and hashCode() methods are implemented.
   14. Casting from or to an immutable class does boxing or
unboxing.
   15. They cannot be compared to or assigned null.

Immutable classes have to be final (or have all their
methods final a less satisfactory solution) otherwise they
could have a method overridden to return a mutable value.
Private constructors with static factories are in some ways
better than using constructors to create objects (Effective
Java Item 1), it impossible to extend a class with only
private constructors so it is effectively final

Instance variables have to be final, and should be private,
using accessors allows the implementation to be changed.

Lazy construction is sometimes necessary for performance
reasons, its probably best to make the field volatile to
indicate that it is not part of the externally visible
state. (see Effective Java, Item 13).

Continued ...


Submitted On 19-DEC-2002
M.R.Atkinson
I suspect that if synchonization is allowed on Immutable
objects it would force them to be reference types. Opps,
this should have been included in the list for additional
requirements for lightweight objects.

Threads started in the constructors allow Imutable objects
to become mutable and unpredictable, see "If I Were King: A
proposal for fixing the Java programming language's
threading problems", Allen Holub.
http://www-106.ibm.com/developerworks/java/library/j-king.html

public class Broken {
   private long x;
   Broken() {
      new Thread() {
         public void run() {
            x = -1;
         }
      }.start();
      x = 0;
   }
}

The thread that sets x to -1 can run in parallel to the
thread that is running the constructor which sets x to 0.
Consequently, the value of x is unpredictable.


Similarly writing to static variables allow half constructed
objects to be observered:

public class Test {
   public static Test test;
   private int x;
   private int y;
   public Test(int x, int y) {
      this.x = x;
      test = this;
      this.y = y;
   }
}


Implementing Cloneable does not make much sense, as any
cloned Immutable will be indistinguishable from the original
and will neither will ever change. clone()  also acts
another constructor and can be tricky to get right.

For the reasons outlined in Effective Java, Serializable
Immutable objects should explicitly implement the
readObject() or readResolve() as the default readObject()
would allow an attacker to create a mutable version of your
Immutable class, see Items 13 & 56.

Copy constructors are useless, for the same reason that
clone() is useless, having one in an Immutable class shows a
design error or missunderstanding, the compiler should issue
an error.

Immutable classes should not extend classes that contain
instance variables, I think not even final instance
variables, as this would allow an immutable class to be
modified.

Continued ...


Submitted On 25-JAN-2003
hlovatt
cont.

   4.  They are not allowed to start Threads in any of their
       constructors.
   
   I don't think this is necessary since the fields are 
   final, e.g.:
   
       final long x;

       ThreadStartedInConstructor() {
            new Thread() {
                public void run() {
                    x = -1;
                }
            }.start();
            x = 0;
       }

   Is an error at compile time.


Submitted On 25-JAN-2003
hlovatt
Reply to Mike Atkinson: Sorry for not replying sooner, I use 
bug watch to notify me of changes, unfortunately it didn't 
work for some reason and I have only just realized that you 
posted comments. Taking each of your points in turn:

   1.  They are "final" or contain only private constructors.
   
   Go with the majority it isn't a make or break issue. You 
   can have non-final immutables and they do have some 
uses, 
   e.g. adding new methods. Since the extended type would 
   also be immutable the need for final as suggested by JB 
   in "Effective Java" isn't necessary, he needs final 
   because the compiler doesn't enforce the extended type 
   to be immutable when you 'hand craft' an immutable.
   
   The JVM already knows if a class has an extension loaded,
   it is called "effectively final", therefore it can make
   the object lightweight if there is no extension loaded
   at the time the object was made provided it can back out
   of this decision if an extension class is later loaded.
   
   The JVMs do this for effectively final methods already,
   which they inline until an extension class is loaded.

   2.  All instance variables are private final.
   
   Private is good practice, but again go with the majority,
   it isn't a make or break issue. The definition of 
   immutable used allows for public fields since the fields 
   are final and either primitive or immutable, therefore 
   they can be public, etc.

   3.  All instance variables are primitive types, or
       immutable or contain only final instance variables
       themselves (recursively). There is one exception to
       this, a volatile instance variable may be lazily
       constructed.
       
   I don't get what you mean by instance variables, do you 
   mean instance fields or local variables. Sorry we 
   obviously use different terminology.
   
   I am not good enough at JVMs to know whether this 
   volatile idea is possible. On the general subject of 
   lazy initialization I was hoping that the compiler/JVM 
   could do this automatically, like the language Haskell 
   (http://www.haskell.org/). You don't manually code lazy 
   initialization in Haskell, the compiler just does it.


Submitted On 25-JAN-2003
hlovatt
cont.

   10. An immutable class should not extend another class
       that contains non-static fields.
       
   Except that it can extend other immutable classes, see 1.

   11. No non-private methods are provided that modify
       any of the instance variables.
       
   Since the fields are final and either primitive or 
   immutable then no method, private or otherwise, can 
   modify the fields.

   12. toString() should be implemented, the default
       toString() in Object that gives an objects address
       is not meaningful in lightweight classes.
       
   I favour the compiler supply a toString if the 
   programmer doesn't.

   13. Like primitive instance variables they are cannot be
       synchonized on.
       
   Yes.

   14. a==b maps onto a.equals(b).
   
   Again not a 'show stopper', go with the majority. 
   Another alternative is that == is an error when applied 
   to an immutable.

   15. The equals() and hashCode() methods are
        implemented.

   I favour the compiler supplying these methods if the 
   programmer doesn't.

   16. Casting from or to an immutable class does boxing or
        unboxing.

   Yes.

   17. They cannot be compared to or assigned null.

   Yes, applies all the time since the compiler can't
   check this (it could happen in a class compiled
   seperately).
   
   18. The above does not specify how Immutable will be 
       implemented I have a slight preferrence for adding 
       a keyword, but your points about using a marker 
       interface are well made.
       
   Not a show stopper, go with the majority.


Submitted On 25-JAN-2003
hlovatt
cont.

   6.  Immutable objects must be fully initialized in their
       constructors (except for any volatile fields).
       
   This is ensured by final fields (see 3 above re. 
   volatile).

   7.  They cannot implement Cloneable.
   
   See 8 below.

   8.  If they implement Serializable they must have a
       readObject() or readResolve() implementations that
       obeys the same rules as for constructors.
       
   My original idea was as you stated above, but I have 
   backed away from this because of using immutable types 
   more in my own code. To be able to ensure that a copy of 
   an immutable isn't made you need to keep a list of 
   immutables and compare the new immutable to the list and 
   return the existing one from the list instead of making
   a new one (this is called "const hashing" sometimes). 
   Const hashing can be very slow and use a lot of memory 
   for large objects, therefore just let repeats be made 
   and rely on equals returning true when they are compared.
   These comments also apply to Cloneable, boxing and 
   unboxing, and to making to identical immutables 
   manually, e.g.:
   
       ImmuableInteger i1 = new ImmuableInteger( 1 );
       ImmuableInteger i2 = new ImmuableInteger( 1 );
       
   They are the same! Just like copies made by 
   serialization.

   9.  They cannot contain be a copy constructor.
   
   See 8. Just let people do this if they want; there may 
   be a legitamate reason and it is hard to stop, e.g:
   
       ImmutableType( ImmutableType objectToBeCopied, 
            int extraUnsusedArgumentToFoolCompiler ) { ... }


Submitted On 25-JAN-2003
hlovatt
cont.
   
   5.  They are not allowed to write to any static variable
       in any of their constructors.
       
   You raise an interesting point here. I will widen the 
   discussion to general access to statics either in their 
   own class or in another class. It is in one way odd that 
   an immutable can have a changing value via a static, but 
   all the immutables of that type will always have the 
   same value. Therefore it is not like two immutable that 
   were the same sudenly become different, they both change 
   together. Since Java has statics I chose to leave this 
   as is and I think this is still the right decision. On 
   a practical note I can't think how you would stop this, 
   e.g.:
   
        public class HidingStaticsInsideInstances 
	                            implements Immutable {
            void accessHiddenStatic() {
                final DifferentClass dc = 
		                      new DifferentClass();
                final int x = dc.accessStaticViaInstance();
                System.out.println( x );
            }

            public static void main( 
	                        final String[] notUsed ) {
                new HidingStaticsInsideInstances().
		                     accessHiddenStatic();
            }
        }

        class DifferentClass {
            static int x = 1;

            int accessStaticViaInstance() {
                return x;
            }
        }


Submitted On 11-FEB-2003
M.R.Atkinson
Opps,
2. All instance variables are private final.

should have said 

2. All instance variables are private or final.

otherwise my point 11. does not make sense.


Submitted On 11-FEB-2003
M.R.Atkinson
Further to rule 1.

while a agree that a sufficiently cleaver JVM could unlearn
all of its optimisations when an extension class for a
(non-final) immutable was loaded, this would cause lots of
unnecessary complications. There are I believe relatively
few cases where immutable classes can be extended without
significantly changing the semantices of most instance methods.

Further to point 3.

I mean instance fields. The lazy intialisation of volatiles
is a performance improvement (which I think works). 

Further to rule 4.

    final long x;

       ThreadStartedInConstructor() {
            new Thread() {
                public void run() {
                    System.out.println(x);  // what gets
written out
                }
            }.start();
            x = 1;
       }
    }

The rule about threads is necessary to avoid half
constructed immutables being visible outside the constructor.



Further to rule 5.

Perhaps a different version of this rule and rule 4. could
be that all fields have to be initialised before methods or
fields of other classes are accessed. I think something like
rules 4&5 are necessary as there seems little point in
adding immutables to the language and them allowing them to
be mutable!


Further to rule 7.

Cloneable makes no sense to implement as the clone will be
indistinguishable from the original. Clones also do not make
sense for a lightwieght class (whose objects may be copied
rahter than passed by reference). Any immutable class that
implemented Cloneable would indicate a conceptual error on
the part of the programmer, as it is easy for a compiler to
pick up then this should be flaged as an error.

Futher to rule 8.

Thinking about it I think rule 8 should be:

   8. If they implement Serializable then their
       readObject() or readResolve() implementations (if
       present) must obey the same rules as for
       constructors.

This is because readObject() and readResolve() are in effect
constructors, and could allow partially constructed
immutables to escape, leading to them being visibly mutable
to other classes.


Futher to rule 9.

Copy constructors indicate a conceptual error on the part of
the programmer and should not be allowed. I agree that a
programmer could fool the compiler if he tried hard enough
but that is no reason for the compiler not to check for the
common mistake.






Submitted On 02-MAR-2003
hlovatt
Reply to Mark Atkinson

I think your rule 2 should say:

All instance fields are final.

Your rule 4 example is subtly different than the previous
example you gave of a thread starting in the constructor.
The previous example changed x, which wasn't possible
because x would be final. The new example simply has this
exposed by using an inner class. Another example of
exposing this is:

package junk;


final class CopyInConstructor {
    final long x;
    final Copy copy;

    CopyInConstructor() {
        copy = new Copy( this );
        x = 1;
    }

    void print() {
        System.out.println( copy.x );
    }

    public static void main( final String[] notUsed ) {
        new CopyInConstructor().print();
    }

    class Copy {
        final long x;

        Copy( final CopyInConstructor original ) {
            x = original.x;
        }
    }
}

The exposure of this in a constructor is a general problem 
in Java and isn't easy to stop. I suggest we let 
immutables behave like the rest of Java and live with 
the problem.


Submitted On 14-DEC-2003
Mike_Atkinson
It looks almost certain now that immutable will not be in
JDK 1.5 as a keyword, and probably not as a marker
interface. It may not yet be too late to include it as an
attribute.

Further to the above discussions, immutables may also be
used in place of "struct" as long as only primitive types
are used and they are packed


Submitted On 08-JAN-2004
hlovatt
Reply to Mike Attkinson - Yes to both your points


Submitted On 19-FEB-2004
hwc
This sounds like a job for annotations!  Instances of an 
@Immutable class would behave rather like primitives: 
they could not change their value after they had been 
constructed and they would have no identity.  Each field 
would be static or final instances of a primitive or 
@Immutable type.  @Immutable classes should not 
be Runnable and should not include synchronized 
methods.

Variables holding a [reference to] an @Immutable 
need not be final, although they often would be, but 
they should always be initialised.  This presents an 
interesting problem: existing classes that followed the 
rules given above might be annotated @Immutable 
and re-compiled without breaking existing code but it 
might not be possible to re-compile that code if, for 
example, lazy initialisation is used.

I suspect @Immutable classes should be final, 
otherwise they should be considered abstract.  If they 
extend anther class, that class should obviously obey 
all the rules given above.

An array of @Immutable values would not itself be 
immutable.  Its elements could never be null, though, 
which suggests the need for a default constructor, 
perhaps machine generated.  Immutable arrays would 
also be useful, either using the Array< Type > syntax or, 
perhaps, @Immutable Type array[].  Elements of an 
immutable array should themselves be primitive or 
@Immutable.

It should be possible to cast any @Immutable to an 
Object.  In many cases this would be a no-op but if the 
JVM stored small @Immutables on the stack, they 
would need to be copied.  Casting an Object back to 
an @Immutable would almost always involve a 
defensive copy. 

The compiler should be able to generate equals() 
[instances of the same type and all member variables 
equal] and hashCode().  The user would normally 
implement toString().  I imagine clone() and a copy 
constructor may be useful in some circumstances for 
auto-boxing and casting from Object repectively.

There should also be an @Immuatable Complex type, 
an ImmutableDate, auto-boxed to java.lang.Date, and 
a StringLiteral, auto-boxed to String, StringBuffer or 
whatever.  Ideally, string constants would be 
StringLiterals.  A Pair or Tuple class would be nice, 
too.  I think it’s too late for Integer and Double – making 
them @Immutable would break too much existing 
code and new classes would offer little benefit over the 
primitive types unless the rules for auto-boxing 
generics changed (C# seems to have the advantage 
here).

Comparison using == would give undefined results.  
Ideally the compiler should flag up an error, e.g.

String input = keyboard.readLine();
if( input == “yes” ) // a common mistake, might be 
spotted by the compiler

However, auto-boxing might kick in at this point.  The 
rules would have to be defined very carefully so that the 
program behaved consistently, whether or not the JVM 
optimised the storage of small objects.  I’m not sure I 
like the idea of == becoming equals() behind the 
scenes but at least that would be predictable.

Like many of the ideas introduced in Java 1.5, these 
changes in themselves should make life a little easier 
for the programmer, reducing common causes of 
error: objects cannot change behind your back, local 
method calls become more like RMI etc.  However, as 
others have pointed out, they also facilitate better code 
optimisation and that must be a good thing.


Submitted On 20-FEB-2004
Nicholas.Goodwin
Although not strictly necessary, I would like immutable 
classes to act as values in JAX-RPC.  They would have 
a public default constructor and not implement 
java.rmi.Remote - OK so far, but they might have final 
public fields and they would not have setter methods 
for their private fields.  Is there any way of reconciling 
these differing requirements?


The problem would Its fields must be JAX-RPC 
supported types. Also, a public field cannot be final or 
transient, and a non-public field must have the 
corresponding getter and setter methods. 


Submitted On 08-MAR-2004
hlovatt
Reply to hwc

Sorry fpor not replying sooner - bug watch failed yet again!

I think  on balance that sticking with an interface is
better for immutables because expressions like:

x instanceof Immutable
class ImmutableCollection< E extends Immutable > ...

Are natural for an interface but not for an attribute.

I agree with all your comments re. boxing, ==, etc.


Submitted On 08-MAR-2004
hlovatt
I have written a compiler available for download that
includes immutables in addition to other features and uses
the concept of a marker interface to identify an immutable.
It is a free download from pec.dev.java.net under the Lesser
GNU Public Licence. Let me know what you think.


Submitted On 08-MAR-2004
hlovatt
Reply to Nicholas.Goodwin

Unfortunately I can't see how you can introduce an immutable
that is compatible with many existing classes, you sight
JAX_RPC and hwc has mentioned Date for example.

I think it is necessary to have a two stage process, first
to introduce the new feature and then to change existing
classes/APIs. This for example is the process for generics,
when introduced in 1.5 we will only have the collections API
that uses them even though many other API could benefit.


Submitted On 11-MAR-2004
hlovatt
Reply to Mike_Atkinson

Thanks for your posting. I agree that exposing the this
pointer during construction is a bad idea but I don't know
the best way to stop it, there are so many different ways of
exposing it! I have given this subject some thought and the
best I have come up with is that the programmer isn't
allowed to write constructors at all, the compiler supplies
a protected one that simply initializes the final fields
from arguments. Then the programmer writes static factories. 

As you point out in your post it was a while ago since we
discussed this and I re-read your original post. Whilst I
think we have broad agreement in many areas some of the
details that you wish are not quite the same as myself. I
have written a compiler that enforces one form of immutable.
You can doenload it under LGPL from pec.dev.java.net. An
interesting feature of this compiler is that you can write
your own immutable, the compiler is extendable. IE you can
take my Immutable and modify it to be Mike's immutable. You
might like to give it a try.


Submitted On 11-MAR-2004
Mike_Atkinson
hlovatt, its now a year since our long discussion on
immutables. The new Memory Model spec (JSR 133) says (secion 9):

"Objects that have only final fields and are not made
visible to other threads during
construction should be perceived as immutable even if
references to those objects are
passed between threads via data races.
– Storing a reference to an object X into the heap during
construction of X does
not necessarily violate this requirement. For example,
synchronization could ensure
that no other thread could load the reference to X during
construction.
Alternatively, during construction of X a reference to X
could be stored into another
object Y ; if no references to Y are made visible to other
threads until after
construction of X is complete, then final field guarantees
still hold."

For immutable object (that may be passed by value, but
needn't, the decission should be up to the JVM)
synchronization cannot be used. So to make objects immutable
really does require that partially constructed instances are
not visible outside the thread that  is creating them. 


Submitted On 24-AUG-2004
PtrBckr
I recently found an experimental programming language which does a distinction between "state objects" and "value objects", which is very much like the distinctions made here and definitely something I'd like to see. There is an overview of the two types here: http://lavape.sourceforge.net/doc/html/TwoObjectCategories.htm

I find this distinction quite useful and I agree that something along these lines would be far better than having "const" and/or "struct".

I'd even scrap equals() and hashCode() for it, if I could :-) At the moment it is just a potential cause of pain when equals() is overridden on a mutable object. Value identity and mutability don't agree.


Submitted On 29-AUG-2004
hlovatt
PtrBckr ,

Thanks for the URL. The Lava proposal is definately along the same lines:

1. Their State objects are normal Java objects

2. Their Value objects are similar to the immutable objects proposed in this RFE

They don't have the concept of a companion mutable class to the immutables and they don't have conversions between mutable and immutable forms.

You can download, under the GNU LGPL, a compiler I have written that conforms closely to this proposal:

http://pec.dev.java.net/

In the compiler whose URL is given above the mutable types are called Value types; the name change was to be more consistent with standard terminology, in particular the term Value semantics appears in Computer Science literature.


Submitted On 09-NOV-2004
lucretiussecundus
hlovatt, great that you've done an implementation of your ideas. But I find your choice of name 'Value' for mutable types very confusing. Java's primitive types are normally spoken of as 'values', but they are immutable.

Maybe you should steer clear of the word 'value' altogether since it's ambiguous?


Submitted On 14-NOV-2004
hlovatt
lucretiussecundus,

Any suggestions for an alternative name? I used Value 
because it is often used in terms like Value Semantics, 
Lightweight Value Semantic Objects, etc.

Just a point about primitives, you can


Submitted On 14-NOV-2004
hlovatt
Cont. - the posting got cutt off!!!!

Just a note about primitives, you can't tell if a primitive is a value type of an immutable in Java because you can't take the address and System.identityHashCode doesn't work for them.

If you use my compiler let me know how you get on.

Cheers.


Submitted On 12-DEC-2004
lucretiussecundus
hlovatt - maybe simply use the term 


Submitted On 27-JAN-2005
gbishop
Why should == be an error or always return false?  What if I am comparing a bunch of things, some immutable, some not?

I don't like all these unnecessary restrictions.  This proposal now that ti's been batted back and forth seams to me to be overly complicated.

I don't like the conversions classes.  I don't like restrictions on subclassing either.  This looks more and more like a glorified version of interface where all the members are public static final values.


Submitted On 27-JAN-2005
hlovatt
The reason for making == an error  is so that this request for an enhancement doesn't get bogged in the operator overloading debate. You could map == to equals for immutables but the concensus in this forum was that it would be better to simply ban == on immutables. Note the default comparison of == based on memory address is almost certainly not what you want, because it will be inconsistent with equals for an immutable, so it is better to ban == than allow the default ==.

The reason for the design with an immutable and a mutable (value) version is for efficiency. If you don't need the mutable version then don't use it. Just use the immutable version. Or don't make the mutable version public.

The reason for converting between the immutable and mutable versions by copying is to avoid the problems associated with const aliasing in C++. The immutables here really are immutable, they do not change and nothing can change them.


Submitted On 20-OCT-2006
pron
This is one of the best RFE proposals I have seen. It is an excellent compromise between enhancement and compatibiliy, and it essentially provides lightweight objects without being a heavyweight change to the language.
If accepted, this RFE may open a whole new horizon to high-performance numeric computation in Java. Finally, we could have decent arrays of complex numbers.
+1


Submitted On 25-OCT-2006
hlovatt
Thanks for you supportive comments. Incidentally complex numbers was one of my motivations for posting this RFE.


Submitted On 26-JAN-2007
By the Liskov Substitution Principle, a List<Integer> is not a subtype of List<Number>. But what about: ImmutableList<Integer> and ImmutableList<Number>? It seems reasonable to me that a singly-linked list could sensibly be implemented as immutable, and it would be nice if such an immutable list would allow more flexible typing.


Submitted On 01-FEB-2007
hlovatt
I agree with the above post, it would be nice if the typing understood immutable and could reason that this was safe since the list itself is immutable.

As an aside I have mixed feelings about this behaviour of generics, in particular I can't recal this ever been a problem for me with arrays and the restriction has been a pain in some code.


Submitted On 11-JUN-2007
Support.
In writing a Java based database, we have had significant pains in the ToMutable use case, which happens when we modify an object as part of *some* write transactions.

Language support would definitely ease our pain.


Submitted On 29-JUN-2007
hlovatt
You can download, under the GNU LGPL, a compiler I have written that conforms closely to this proposal:

http://pec.dev.java.net/

In the compiler whose URL is given above the mutable types are called Value types; the name change was to be more consistent with standard terminology, in particular the term Value semantics appears in Computer Science literature.


Submitted On 12-AUG-2007
I frequently want to create class hierarchies of immutable objects. I don't want such a feature to make all immutable classes final. I do think that any subclasses of an immutable object also need to be immutable, though.



PLEASE NOTE: JDK6 is formerly known as Project Mustang