> --
> You received this message because you are subscribed to the Google Groups
> "Java Language Specification" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/java-language-specification/-/cNuSrAnBuikJ.
> To post to this group, send email to
> java-language...@googlegroups.com.
> To unsubscribe from this group, send email to
> java-language-speci...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/java-language-specification?hl=en.
>
--
Craig Berry
Software Engineer
Google (Santa Monica CA)
--
One might imagine that it would be a runtime error to read a lazy
member before it's been written.
--You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/dsmuXAvcU1kJ.
This sounds like something that could be done at compile-time. Just like accessing a final field before its value has been set.
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/APilI0r26eEJ.
Brad,How do you propose mutability to be checked?
My common-sense reaction was to require all fields to be immutable; there are, however, necessary exceptions, as in Guava's RegularImmutableList, which requires use of an array.
Arrays are necessarily mutable, and Guava has to promise that they are using it in an immutable way. I would suggest a warning in cases where members of a type that is not marked immutable are used in a class marked immutable. Then in cases where this is really what you want, you would add a @SuppressWarnings annotation.
How would lazy be implemented? The double-check idiom? What if one only requires the single-check idiom? java.lang.String famously uses the racy single-check idiom to cache hash codes.
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/8vlJs98YM6sJ.
So, how would you deal with a final instance of a mutable class. For example, suppose I hadprivate final List<String> products;as an instance variable. What would prevent me from calling getProducts().add(productNumber)?If, on the other hand, you had a rule that instance variables must be immutable, you would get a warning on the above (because List is not an immutable type); you would then switch to ImmutableList, which would be marked immutable, and the compiler would be happy.
As a general rule, the earlier you can find a problem, the better. That is, in fact, what I would find attractive about an immutable keyword (or annotation). In the case of hashCode, all access to that field would typically be in a single method. My lazily-cached hashCode implementations typically are similar to the following:private transient volatile hashCode;public int hashCode() {int hashCode = this.hashCode;if (hashCode == 0) {hashCode = this.hashCode = Objects.hashCode(a, b, c);}return hashCode;}Perhaps instead you would have something like the following:private transient final lazy hashCode;public lazy hashCode() {this.hashCode = Objects.hashCode(a, b, c);return this.hashCode;}
The first time this method is accessed, it will populate hashCode. Any future accesses to that method would simply return the cached value.This is probably not exactly how you'd do it... just trying to push in the direction of a) don't make the programmer do something so complicated he is liable to shoot himself in the foot (e.g., the double-check idiom, which is the only one that ought to pass the test), and b) be able to reliably guarantee that the class will be immutable with the exception of lazy-initialized fields, which would be guaranteed to be initialized once.
I think that kind of defeats the point of immutability: clients should never see a change in state. If multiple calls are made to retrieve a lazy value, they should probably just block until it's computed. Another possibility is that lazy values can only be calculated from the state of other immutable values, such that any data races that occur in retrieving it are guaranteed to be benign (a la String's hashCode()).
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/EBSsAnjW3D0J.
I've given this a little more thought, and I'm rather reluctant about the lazy keyword. I think your immutability constraint can be satisfied without it.Suppose you had a class like the following:public immutable abstract class Lazy<T> {private volatile T value;
public abstract T initialize();public T get() {T value = this.value;if (value == null) {synchronized(this) {value = this.value;if (value == null) {this.value = value = initialize();}}}return value;}}then in your immutable Foo class, you could have:private final Lazy<Integer> hashCode = new Lazy<Integer>() {public Integer initialize() {return Objects.hashCode(a, b, c);}}public int hashCode() {return hashCode.get();}
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/htPtwfNQ4MYJ.
Not quite. I failed to add the @SuppressWarnings annotation I'd alluded to earlier. You're right that any old user can do this himself... but, as you mentioned, do you really want to rely on people trying to remember the various lazy-initialization idioms, and most likely getting it wrong? Particularly if you want to enforce the "this can absolutely be set only once under any circumstances" rule, everyone has to use the double-check idiom, which is, of course, the hardest one to get right.
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/vq8y-ZNxxK4J.
This would not be unlike the static keyword. static methods can only use class-level variables that are static. Likewise lazy methods could only use immutable methods and immutable class-level variables.
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/DuSXZ1JE_zcJ.
Your class is mutable:new AnImmutableClass(1, 1, 1, new Data[]{new Data("ray", 112, 17)}).dataList.removeAll();
Why even have the var at all?
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/BOPoNUh8piEJ.
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/3Qwcfo4_v4EJ.
What I meant was that you could just have:private lazy int hashCode() {return Objects.hashCode(a, b, c);}And the lazy modifier on the method could control the caching of the value once it's initialized. In other words, why even declare the var yourself--instead, just define the method and let the JVM do the work.
Fair enough--I hadn't noticed the wrapping you did in the constructor. But thats the point--you're not communicating immutability of the members, nor can you enforce it early. Just force use of immutable classes, and nobody could make the mistake of forgetting to wrap it.
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/p8dWyp7f4ZIJ.
private final lazy int hash = Objects.hashCode(a, b, c);
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/033iLX5GLskJ.
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
To view this discussion on the web visit https://groups.google.com/d/msg/java-language-specification/-/LZvrvuL1vNIJ.
I guess I'm a bit confused about this... Guava already provides ImmutableList that is immutable and can convert any iterable to an ImmutableList. What's missing?
--
You received this message because you are subscribed to the Google Groups "Java Language Specification" group.
On Aug 5, 2:09 am, BradW <b....@willcott.com> wrote:
> http://jdk-immutability.java.net/
I'd say your "lazy" is a bit too complicated. What about simply
private lazy int hashCode() {
int h = 7;
h = 31 * h + name.hashCode();
return h;
}
public final lazy int hash = hash(); // Method call not made until variable is referencedyou get to use a method to initialize a final lazy instance variable. Furthermore, the method is called by the JVM only once. That being, the
public int hashCode(){ return hash; }
private lazy int hash(){ int h = id; h = 31 * h + name.hashCode(); return h; }has the lazy modifier to designate it to be the init method for the final lazy hash variable. The naming is specific. Note that this is private, and uses the actual variable name, because it is declared above as the field's initializer method: hash = hash();. This keeps it simple. No ambiguity.
You wrote
> public /* final lazy */ int hash; /* = hash(); */ // Method call not made until variable is referenced
This means you need an implicit boolean variable tracking if hash was
already referenced.
IMHO, nearly always the approach taken by String.hashCode() suffices:
Zero means either that the result wasn't computed yet, or that you
were unlucky enough to get 0 as a result. Unlucky because it means
that the value gets computed again and again. Fortunately, it's quite
improbable and so taking the risk is better than spending 4 or 8 bytes
(needed for a boolean considering the alignment). I'm not sure if
there are situations where you need to avoid the risk.
public final int hash;and would be treated as such until the class instance is discarded. In the JVM, these modifiers are stored as bits in an int. So the JVM would just flip the lazy bit to off, and no more lazy variable. Simple!
PS: The above hashCode doesn't make much sense, you probably meant
"int h = id" on the first line.
public final lazy int hash;No explicit method in the field's declaration. Using the method declaration and naming convention already stated, you could use either of the following method types:
public final lazy boolean done;
private lazy int hash(){ int h = id; h = 31 * h + name.hashCode(); return h; }
public final lazy void setDone(){ done = true; }With hash the method is private, so it uses the variable name as the method name. The "hash = hash()", would be implied.
Translating "get" and "set" looks extremely silly to me. In order forthis to make sense you'd need to translate all the standard classes as
well. Moreover, there may be different translation for the prefixes
leading to confusion. It could get even more funny in an international
company.
The only non-English identifiers I use are domain-specific names (here
the translation would be counterproductive, and possibly ambiguous). I
use words composed of words of English and other language and it seems
quite natural to me.
I still don't see the need for the lazy modifier on the hash field.
Your example:
public final lazy int hash = makeBrownies();
private lazy int makeBrownies(){
...
}Might as well be written as:public final int hash = makeBrownies();
private lazy int makeBrownies(){
...
}
I agree totally. "set", "get" and "is" should NOT be translated/internationalized, which I have never advocated. What I claim is that the java bean naming convention should never have seen the light of day. Java should have supported first-class-properties from day one to prevent relying on method naming conventions to link fields with methods. I don't even think this is a very contentious opinion. Have a look at C# properties for a way to implement first class properties in a type-safe and unambiguous way.
Mind you, this is a derail of the "lazy" spec, which in itself is a slight derail of the core subject of this thread (immutable class modifier), so I'll rest my case.