This is a branch from the general purpose it-block proposal to discuss how mutable and immutable objects provide default clone/change support.
One of the things I proposed is this shortcut:
obj { ... } // shortcut
obj.with({...}) // long hand for above
Let's assume that we desire this behavior:
On a non-const object, the it-block is applied immediately
On a const object, the it-block is applied to a of clone object
If that is the specified behavior, then maybe we just define the following method on Obj:
This with(|This| itBlock)
{
if (type.isConst)
{
copy := this.clone
itBlock(copy)
return copy
}
else
{
itBlock(this)
return this
}
}
The tricky thing is that immutable classes can only have their fields set by their constructor. This means that clone must somehow pass every field set and the itBlock into the class's constructor. I no idea what that looks like.
JohnDGWed 25 Mar 2009
The tricky thing is that immutable classes can only have their fields set by their constructor. This means that clone must somehow pass every field set and the itBlock into the class's constructor. I no idea what that looks like.
In the builder proposal, it would actually be possible to compute the composite of two builders for the same type, and then apply just the net effect.
With closures/itBlocks, no such solution is possible because every change is immediately enacted on the specified object.
However, there is a possible workaround: construct a mutable clone, apply the changes with an itBlock, and then create an immutable clone. This approach requires substantial reworking, as every immutable object would have to have a corresponding mutable version (even if just hidden behind the scenes).
I suggest something simpler: the fields of a const object needn't be final, and with needn't have a Fan implementation. This frees you to do whatever you want in with even if it doesn't have an implementation in Fan source code.
tompalmerWed 25 Mar 2009
No particular recommendations, but easily tweaked copies of immutable objects does seem very nice to me.
jodastephenThu 26 Mar 2009
If the immutable constructor at the bytecode level takes in an instance of the same type, then it can copy all the fields from the object, before calling the it-block:
public final class Immutable {
private String foo;
public Immutable(...) { ... } // public constructor
private Immutable(Immutable copyFrom, ItBlock b) {
this.foo = copyFrom.foo;
v.apply(this);
}
}
Care would be needed with the Java Memory Model though.
Certainly, the builder approach offered better solutions here. However it suffered from no easy way to call arbitrary code. (Overall, I'm a little worried by the sheer number of classes that it-blocks will actually create)
I'd also like to see a modifier/keyword/annotation that ensures that the value returned from a method is actually used:
Str s = "foo"
s.upper() // I want this to not compile
This avoids a class of bug. This concept is relevant here, as the immutable with method should force callers to assign (or use in a method call) the result.
brianThu 26 Mar 2009
When I dig into this, I am going to try and see if I can make const fields final in the JVM bytecode. That will force a solution on most of these issues.
Although at this point, I don't think we have to make those fields final for the JMM. There are really only cases where immutables are shared b/w threads - static fields which are guaranteed safe publication by JMM, and message passing b/w actors which will force a safe publication via synchronization.
I'd also like to see a modifier/keyword/annotation that ensures that the value returned from a method is actually used
Great idea, what would you call it though?
JohnDGThu 26 Mar 2009
I'd also like to see a modifier/keyword/annotation that ensures that the value returned from a method is actually used:
You could do this automatically for const classes, because an immutable class cannot affect any state change, if a return value is not used, then it's probably a bug.
e.g. Java 101 bug: using String.replace and ignoring the return value.
Although at this point, I don't think we have to make those fields final for the JMM.
No, I don't think you have to, because even thread-local caching will produce safe semantics for fields that do not change post construction, whether or not those fields are declared final, because they won't be cached until another thread accesses them, by which point they are fixed for life.
Well, it seems like everyone is on board with this proposal; only technical details remain to be sorted out.
Re: clone. Perhaps clone could optionally accept an itBlock that would customize the clone details? Then you can have a Fan implementation of with (inlined & optimized by the compiler to immediate execution), and the magic goes inside clone.
jodastephenThu 26 Mar 2009
I'd also like to see a modifier/keyword/annotation that ensures that the value returned from a method is actually used
Great idea, what would you call it though?
A new keyword?
class Foo {
assigned Foo clone() {
}
}
An annotation?
class Foo {
@Assigned
Foo clone() {
}
}
It feels like overide to me, which is why I'd prefer a keyword. Const classes have it implied on all methods returning non-Void.
Overall, I think you should try implementing something based around what we've discussed. I suspect that you'll find some issues as you implement, which may then need more discussion.
brian Wed 25 Mar 2009
This is a branch from the general purpose it-block proposal to discuss how mutable and immutable objects provide default clone/change support.
One of the things I proposed is this shortcut:
Let's assume that we desire this behavior:
If that is the specified behavior, then maybe we just define the following method on Obj:
The tricky thing is that immutable classes can only have their fields set by their constructor. This means that
clone
must somehow pass every field set and the itBlock into the class's constructor. I no idea what that looks like.JohnDG Wed 25 Mar 2009
In the builder proposal, it would actually be possible to compute the composite of two builders for the same type, and then apply just the net effect.
With closures/itBlocks, no such solution is possible because every change is immediately enacted on the specified object.
However, there is a possible workaround: construct a mutable clone, apply the changes with an itBlock, and then create an immutable clone. This approach requires substantial reworking, as every immutable object would have to have a corresponding mutable version (even if just hidden behind the scenes).
I suggest something simpler: the fields of a
const
object needn't befinal
, andwith
needn't have a Fan implementation. This frees you to do whatever you want inwith
even if it doesn't have an implementation in Fan source code.tompalmer Wed 25 Mar 2009
No particular recommendations, but easily tweaked copies of immutable objects does seem very nice to me.
jodastephen Thu 26 Mar 2009
If the immutable constructor at the bytecode level takes in an instance of the same type, then it can copy all the fields from the object, before calling the it-block:
Care would be needed with the Java Memory Model though.
Certainly, the builder approach offered better solutions here. However it suffered from no easy way to call arbitrary code. (Overall, I'm a little worried by the sheer number of classes that it-blocks will actually create)
I'd also like to see a modifier/keyword/annotation that ensures that the value returned from a method is actually used:
This avoids a class of bug. This concept is relevant here, as the immutable with method should force callers to assign (or use in a method call) the result.
brian Thu 26 Mar 2009
When I dig into this, I am going to try and see if I can make const fields final in the JVM bytecode. That will force a solution on most of these issues.
Although at this point, I don't think we have to make those fields final for the JMM. There are really only cases where immutables are shared b/w threads - static fields which are guaranteed safe publication by JMM, and message passing b/w actors which will force a safe publication via synchronization.
Great idea, what would you call it though?
JohnDG Thu 26 Mar 2009
You could do this automatically for
const
classes, because an immutable class cannot affect any state change, if a return value is not used, then it's probably a bug.e.g. Java 101 bug: using String.replace and ignoring the return value.
No, I don't think you have to, because even thread-local caching will produce safe semantics for fields that do not change post construction, whether or not those fields are declared
final
, because they won't be cached until another thread accesses them, by which point they are fixed for life.Well, it seems like everyone is on board with this proposal; only technical details remain to be sorted out.
Re: clone. Perhaps
clone
could optionally accept an itBlock that would customize the clone details? Then you can have a Fan implementation ofwith
(inlined & optimized by the compiler to immediate execution), and the magic goes insideclone
.jodastephen Thu 26 Mar 2009
A new keyword?
An annotation?
It feels like
overide
to me, which is why I'd prefer a keyword. Const classes have it implied on all methods returning non-Void.Overall, I think you should try implementing something based around what we've discussed. I suspect that you'll find some issues as you implement, which may then need more discussion.