On 31 March 2010 17:14, Bert Freudenberg bert@freudenbergs.de wrote:
On 31.03.2010, at 16:10, Igor Stasenko wrote:
On 31 March 2010 16:07, Bert Freudenberg bert@freudenbergs.de wrote:
On 31.03.2010, at 15:03, Igor Stasenko wrote:
On 30 March 2010 14:09, Bert Freudenberg bert@freudenbergs.de wrote:
On 30.03.2010, at 11:45, Bryce Kampjes wrote:
On Thu, 2010-03-18 at 16:40 +0100, Bert Freudenberg wrote: > On 18.03.2010, at 16:30, Ralph Johnson wrote: >> >> On 3/18/10, Bert Freudenberg bert@freudenbergs.de wrote: >> >>> With true immutables you can start developing in a mixed object/functional style, which would allow interesting optimizations, e.g. for concurrency, memoization etc. >> >> I've developed in a mixed object/functional style for years, and I >> think a lot of other people do, too. You don't need language support >> for this, though I expect it would be helpful. It makes concurrency >> and distributed programming easier, and is important when you are >> dealing with databases. Eric Evans calls this "Value Object" in his >> book "Domain Driven Design". >> >> -Ralph Johnson > > Right, the style is possible without VM support in your own subsystem. But being able to *guarantee* immutability would allow to generalize this beyond your own special-purpose code. And possibly it would enable further VM-level optimizations.
Even perfectly VM enforced immutability isn't enough to allow optimisation if you still allow become:. It's always possible to swap out the immutable object with a different one via become:.
It's fine to swap immutable objects, unless the object holding the reference is itself unmutable. No instance variable of an immutable object can be stored into, not even by become:. Obviously, become: would have to honor the immutability flag:. For references inside immutable objects, become: becomes a forward-become (or a no-op if both were immutable):
a := Array with: A new. b := Array with: B new beImmutable. c := (Array with: C new) beImmutable. a first become: b first. "a points to the immutable B instance, b to the A instance". a first become: c first. "both a and c now point to the immutable C instance"
one of the problem with #become:/becomeForward: that it should swap all of existing references atomically. Now imagine that while walking the heap, it replaced a 50% of references to given object, and then discoreved that it needs to swap a reference held by immutable object. Now, what you suppose to do? Revert all changes and fail primitive? Ignore this object (do not alter it references) and continue? Or, before doing the real swapping, scan the heap and check all object to make sure that none of them are immutable and so, #become will work ok?
Just ignore all writes into immutable objects (that is, in the become code, do not insert a forwarding block), otherwise proceed as usual.
But such semantics is no longer can be treated as #become (or #becomeForward), because you leaving a references to old object instead of uniformly replacing them with swapped one.
I don't see a problem with that. Can you give an example where it would be problematic?
It defeats a purpose of #become. If you think about objects as a nodes in directed graph, then become is a way to replace a single node with another one, such that all nodes pointing to node A, now start pointing to node B. If you make any exceptions, you'll end up with having part of nodes in graph pointing to B, while another part still pointing to node A. Many things in system relying on such semantics, and i don't even want to guess, how many places will break if you change that, because in all cases where one using #become, he expects that all references is replaced, but now he should keep in mind that some references keep unchanged and moreover, you don't have a reliable control over this process. So, instead of simple and predictable behavior, #become will be something unreliable and brittle, which cannot be fully trusted.
- Bert -