Immutability and become

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Immutability and become

Bert Freudenberg
On Tue, Jul 18, 2017 at 4:46 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, Bert Freudenberg wrote:

    ​I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.


​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
      On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.


​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean
immutable, no?

#become: would become slow again if we had to find all objects referencing the one we're about to swap. Or, we'd have to make the whole object graph immutable when we make an object immutable. In that case #become: could just fail when the receiver or the argument is immutable.
 
​+1 for making the whole object graph be immutable. And "mutableObj becomeForward: immutableObj copyHash: false" should be the only allowed become case.

- Bert -

- Bert -​



Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

Nicolas Cellier


2017-07-18 16:51 GMT+02:00 Bert Freudenberg <[hidden email]>:
On Tue, Jul 18, 2017 at 4:46 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, Bert Freudenberg wrote:

    ​I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.


​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
      On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.


​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean
immutable, no?

#become: would become slow again if we had to find all objects referencing the one we're about to swap. Or, we'd have to make the whole object graph immutable when we make an object immutable. In that case #become: could just fail when the receiver or the argument is immutable.
 
​+1 for making the whole object graph be immutable. And "mutableObj becomeForward: immutableObj copyHash: false" should be the only allowed become case.


What if I change a class or superclass of an immutable?
(think add or remove an instance variable)
 
- Bert -

- Bert -​







Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

Clément Béra
Hi all,

I am not sure that's what you are talking about, as there is no true immutability in the Cog VM but only read-only objects (terminology agreed upon on the VM mailing list after multiple long discussions and I will ignore further discussions on this matter), but in the case of the supported read-only objects, the VM checks if the object is read-only when performing become and *fails* the primitive if so. This is done when checking if the oop is a valid become object (hence, I believe in the case of becomeForward, only one object is checked). Among multiple reasons (implementation details, complexity, tricky cases, etc.), it was implemented this way as it is simpler and it is possible to write a work-around that way:

readOnlyObject beWritableObject.
readOnlyObject become: anotherWritableObject.
readOnlyObject beReadOnlyObject.

However, if at some point someone implements true immutability (i.e. the object cannot be modified once created immutable and cannot be writable again) in the VM, then the work-around does not work and one could consider alternatives.

Best,

On Tue, Jul 18, 2017 at 5:36 PM, Nicolas Cellier <[hidden email]> wrote:


2017-07-18 16:51 GMT+02:00 Bert Freudenberg <[hidden email]>:
On Tue, Jul 18, 2017 at 4:46 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, Bert Freudenberg wrote:

    ​I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.


​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
      On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.


​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean
immutable, no?

#become: would become slow again if we had to find all objects referencing the one we're about to swap. Or, we'd have to make the whole object graph immutable when we make an object immutable. In that case #become: could just fail when the receiver or the argument is immutable.
 
​+1 for making the whole object graph be immutable. And "mutableObj becomeForward: immutableObj copyHash: false" should be the only allowed become case.


What if I change a class or superclass of an immutable?
(think add or remove an instance variable)
 
- Bert -

- Bert -​











Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

Eliot Miranda-2
In reply to this post by Bert Freudenberg
Hi Bert,

On Tue, Jul 18, 2017 at 7:51 AM, Bert Freudenberg <[hidden email]> wrote:
On Tue, Jul 18, 2017 at 4:46 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, Bert Freudenberg wrote:

    ​I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.


​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
      On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.


​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean
immutable, no?

#become: would become slow again if we had to find all objects referencing the one we're about to swap. Or, we'd have to make the whole object graph immutable when we make an object immutable. In that case #become: could just fail when the receiver or the argument is immutable.
 
​+1 for making the whole object graph be immutable.

This really doesn't make sense as it prevents any kind of change at all, e.g. to the class hierarchy, and as Nicolas points out, prevents updating objects if their class definitions are modified.

When we added "immutability" to VisualWorks (actually read-only objects) we held off, and made only literals immutable.  I'd like to see us make CompiledMethods immutable too, but this wold introduce complications in condensing changes/sources, adding/deleting breakpoints, etc.  One can provide an exception handler or a beMutableWhile: facility to make it easy to temporarily make read-only objects writable.

Or are you meaning that when an object is made immutable all its sub-state is made immutable too?  (An idea I have no problems with, provided it does't imply that classes can't change).
 
And "mutableObj becomeForward: immutableObj copyHash: false" should be the only allowed become case.

Agreed. 

- Bert -

_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

Eliot Miranda-2
In reply to this post by Clément Béra
Hi Clément,

On Tue, Jul 18, 2017 at 9:01 AM, Clément Bera <[hidden email]> wrote:
Hi all,

I am not sure that's what you are talking about, as there is no true immutability in the Cog VM but only read-only objects (terminology agreed upon on the VM mailing list after multiple long discussions and I will ignore further discussions on this matter), but in the case of the supported read-only objects, the VM checks if the object is read-only when performing become and *fails* the primitive if so.

Except that we made a mistake and didn't check for a read-only target.  Not that that's an issue in this bug because the default becomeForward: in Squeak and Pharo has copyHash true (why I'm not sure yet; seems very dangerous to me :-) ), and Squeak doesn't have read-only literals yet. So the bug in this case was modifying the hash of #normal and hence causing failures to find #normal in MethodDictionaries.  So while I'm fixing the VM code, it won't prevent this crash.  I've asked Bert for the rationale of making copyHash true by default.
 
This is done when checking if the oop is a valid become object (hence, I believe in the case of becomeForward, only one object is checked). Among multiple reasons (implementation details, complexity, tricky cases, etc.), it was implemented this way as it is simpler and it is possible to write a work-around that way:

readOnlyObject beWritableObject.
readOnlyObject become: anotherWritableObject.
readOnlyObject beReadOnlyObject.

However, if at some point someone implements true immutability (i.e. the object cannot be modified once created immutable and cannot be writable again) in the VM, then the work-around does not work and one could consider alternatives.

Best,

On Tue, Jul 18, 2017 at 5:36 PM, Nicolas Cellier <[hidden email]> wrote:


2017-07-18 16:51 GMT+02:00 Bert Freudenberg <[hidden email]>:
On Tue, Jul 18, 2017 at 4:46 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, Bert Freudenberg wrote:

    ​I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.


​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
      On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.


​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean
immutable, no?

#become: would become slow again if we had to find all objects referencing the one we're about to swap. Or, we'd have to make the whole object graph immutable when we make an object immutable. In that case #become: could just fail when the receiver or the argument is immutable.
 
​+1 for making the whole object graph be immutable. And "mutableObj becomeForward: immutableObj copyHash: false" should be the only allowed become case.


What if I change a class or superclass of an immutable?
(think add or remove an instance variable)
 
- Bert -

- Bert -​















--
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

timrowledge
In reply to this post by Eliot Miranda-2

> On 18-07-2017, at 1:10 PM, Eliot Miranda <[hidden email]> wrote:
>
> ​+1 for making the whole object graph be immutable.
>
> This really doesn't make sense as it prevents any kind of change at all, e.g. to the class hierarchy

Well, of course, really truly making it immutable would have to make everything in the image immutable too, so that nothing in its context could change.

T’would certainly reduce future maintenance effort...

tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
A bug in the code is worth two in the documentation.



Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

Bert Freudenberg
In reply to this post by Eliot Miranda-2
On Tue, Jul 18, 2017 at 10:10 PM, Eliot Miranda <[hidden email]> wrote:
Hi Bert,

On Tue, Jul 18, 2017 at 7:51 AM, Bert Freudenberg <[hidden email]> wrote:
​+1 for making the whole object graph be immutable.

This really doesn't make sense as it prevents any kind of change at all, e.g. to the class hierarchy, and as Nicolas points out, prevents updating objects if their class definitions are modified.

When we added "immutability" to VisualWorks (actually read-only objects) we held off, and made only literals immutable.  I'd like to see us make CompiledMethods immutable too, but this wold introduce complications in condensing changes/sources, adding/deleting breakpoints, etc.  One can provide an exception handler or a beMutableWhile: facility to make it easy to temporarily make read-only objects writable.

Right.​

Or are you meaning that when an object is made immutable all its sub-state is made immutable too?  (An idea I have no problems with,

​Yes, that. Which means that immediates and nil/true/false should become immutable too. In fact, isn't any stateless object already immutable?
 
provided it does't imply that classes can't change).

​The class should not be made immutable​, agreed, but you shouldn't be able change the shape of instances, me thinks.

​- Bert -​
 


Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

Eliot Miranda-2


On Tue, Jul 18, 2017 at 2:22 PM, Bert Freudenberg <[hidden email]> wrote:
On Tue, Jul 18, 2017 at 10:10 PM, Eliot Miranda <[hidden email]> wrote:
Hi Bert,

On Tue, Jul 18, 2017 at 7:51 AM, Bert Freudenberg <[hidden email]> wrote:
​+1 for making the whole object graph be immutable.

This really doesn't make sense as it prevents any kind of change at all, e.g. to the class hierarchy, and as Nicolas points out, prevents updating objects if their class definitions are modified.

When we added "immutability" to VisualWorks (actually read-only objects) we held off, and made only literals immutable.  I'd like to see us make CompiledMethods immutable too, but this wold introduce complications in condensing changes/sources, adding/deleting breakpoints, etc.  One can provide an exception handler or a beMutableWhile: facility to make it easy to temporarily make read-only objects writable.

Right.​

Or are you meaning that when an object is made immutable all its sub-state is made immutable too?  (An idea I have no problems with,

​Yes, that. Which means that immediates and nil/true/false should become immutable too. In fact, isn't any stateless object already immutable?

Almost.  One can still do

    someClass adoptInstance: aStatelessObject
    aStatelessObject becomeForward: anOtherObject
    aStatelessObject pin
    aStatelessObject unpin

provided it does't imply that classes can't change).

​The class should not be made immutable​, agreed, but you shouldn't be able change the shape of instances, me thinks.

There are circumstances where that isn't the right thing to do, because read-only-ness can be overloaded:

- Object-to-database mappers may set read-only-ness on objects to intercept modifications (e.g. to add objects to a "to be written back" set).  It would be the manager's responsibility to handle the necessary temporary relaxation of read-only-ness when an object read-only for the purposes of the mapper has its shape changed.

- Debuggers may set read-only-ness to catch assignments.

Hence the exception raised for read-only violations needs to be rich enough to allow these kinds of things.  The idea is to have a read-only-ness manager that registers managers for objects, and defers to the relevant manager(s) to handle read-only-ness on error.

But since there will always be the primitives to set and unset read-only-ness, read-only-ness may not be in effect for the entirety of an object's lifetime, only most of the time.

​- Bert -​
 
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Immutability and become

Chris Muller-3
In reply to this post by Eliot Miranda-2
I'm sure this has been discussed but...    since become only swaps
pointers, sending it to immutable object itself should be fine, as
long as all of the objects *referencing it* were not read-only, since
that would result in their being mutated..

> Or are you meaning that when an object is made immutable all its sub-state
> is made immutable too?  (An idea I have no problems with, provided it does't
> imply that classes can't change).

What is "sub-state" in a graph with cycles?  Probably best for low
level methods like this to operate on single objects.  Letting a
primitive like that operate an graphs would be too little control for
the framework.