1

I have a class with an instance variable var.
I don't want the variable to be modified / assigned to a value except when the object is created using a Class method.

isImmutable: aBoolean is the method to convert a mutable object to an immutable object and vice-versa.
Can someone please provide me the correct syntax to do it?

Aditya Kappagantula
  • 564
  • 1
  • 7
  • 21
  • I implemented it by modifying the accessor method like this: var1: anObject var1 := anObject. self isImmutable: true. Is there any other better way to do this? – Aditya Kappagantula Nov 10 '13 at 02:19

4 Answers4

0

I haven't tried it, but I'm pretty certain that isImmutable won't do the trick. Assuming that does actually make an object immutable, it will make the object pointed to by the instVar immutable, not the instvar itself.

Your best bet is to simply not include a specific Mutator for the variable at all, but to instead set it at initialization time like this:

MyClass class>>newWithFoo: aFoo
   ^self basicNew initializeWithFoo: aFoo; yourself

MyClass>>initializeWithFoo: aFoo
   self initialize.
   foo := aFoo.

That way, the only way anyone outside the class itself can affect the variable is by creating a new instance by calling MyClass newWithFoo:

(Not counting using reflective methods like #instVarNamed:put: - there's pretty much nothing you can do about them, but anyone using them knows they're breaking the contract of the class anyway).

Stuart Herring
  • 899
  • 6
  • 9
  • Stuart Herring I heard that modifying/implementing basicNew is not a good object oriented design practice. Please correct me if I am wrong. – Aditya Kappagantula Nov 11 '13 at 09:30
  • 1
    I didn't suggest that you modify or implement basicNew - only that you call it. What I suggested was one of two common was of creating a class side instance creation method - you usually either call `#new`, and then public setters for the values you want to set, or you call `#basicNew` and explicitly call an initialization method that will set the initial values (which allows you to not have a public setter for those variables, effectively giving you immutability). – Stuart Herring Nov 11 '13 at 22:53
0

why do you want to make the object immutable? Isn't it enough to declare your API in a way that makes it obvious how to use the class and to not replace the instance variable?

Karsten
  • 2,772
  • 17
  • 22
0

I implemented it using the code:

MyClass class>>classMethod: aValue

anObject := self new value:aValue.
anObject isImmutable: true.
^anObject.
Aditya Kappagantula
  • 564
  • 1
  • 7
  • 21
0

One thing to keep in mind is that immutability operates at a single level in the object graph. Instance variables are a bit like a constant pointer in C++, the address cannot change, but the contents can change.
Here is a little example:

| a b |
a := Array with: 1.
b := Array with: a.
b beImmutable.
b at: 1 put: nil.
^b

Will end up with a NoModificationError, you cannot write any instance/indexed variable of b since b is immutable.
But you can write into the objects pointed by the instance/indexed variables of b:

| a b |
a := Array with: 1.
b := Array with: a.
b beImmutable.
a at: 1 put: 2.
^b

Will succeed, and b is now #(#(2)) instead of #(#(1))

You can also arrange to propagate the immutability further down the object graph if ever that's what you are after (but beware of cycles).

aka.nice
  • 9,100
  • 1
  • 28
  • 40