# Simulating single assignment in Ruby

**URL:** <https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444>\
**Category:** Ruby\
**Created:** [May 18, 2007, 2:10am UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444 "2007-05-18T02:10:55Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 18, 2007, 2:10am UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/1 "2007-05-18T02:10:55Z")

</div>

Hi,

Is there a way to freeze instance variables in Ruby in order to make  
them single assignment? I’m just wondering if there’s a way to simulate  
Erlang in this regard as a way to avoid side effects.

I don’t want to simply not define (or undefine) a setter method because  
you could still get at the instance variable via instance\_variable\_set.  
Redefining instance\_variable\_set won’t work either, because that method  
is apparently not called when performing direct assignment of instance  
variables. I tried calling the freeze method on the instance variables  
directly but that didn’t seem to work either.

Is it possible?

Regards,

Dan

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 18, 2007, 2:55am UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/2 "2007-05-18T02:55:59Z")

</div>

On 5/17/07, Daniel B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> either.  
> Do it differently:

require ‘digest/md5’

class Module  
def erl\_accessor(\*names)  
names.each do |name|  
var = “@\_#{Digest::MD5.hexdigest(rand(65536).to\_s + name.to\_s)}”  
define\_method(name) { || instance\_variable\_get(var) }  
define\_method(“#{name}=”) { |v|  
instance\_variables.include? var and raise “Cannot change  
@#{name}.”  
instance\_variable\_set(var, v)  
}  
end  
nil  
end  
end

class Foo; erl\_accessor :bar, :baz; end

foo = Foo.new  
foo.bar = 5

Since your actual instance variables aren’t related to the names, you  
can only access through accessors.

-austin

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 18, 2007, 10:53pm UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/3 "2007-05-18T22:53:23Z")

</div>

Austin Z. schrieb:

> ```
> instance_variables.include? var and raise "Cannot change 
> 
> ```
> 
> @#{name}."  
> instance\_variable\_set(var, v)

What about Thread safety here?  
I think you would have do lock before the variable is tested.  
If another thread were to assign the same variable  
just after the test and before the last line is executed,  
then other assignment would be lost, wouldn’t it?

I stumbled over this, because this issue also came up  
with my proposal of a “growth-allowing freeze”-state of objects.

Regards  
Sven

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 19, 2007, 5:32pm UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/4 "2007-05-19T17:32:52Z")

</div>

On May 17, 2007, at 6:10 PM, Daniel B. wrote:

> performing direct assignment of instance variables. I tried calling  
> the freeze method on the instance variables directly but that  
> didn’t seem to work either.
> 
> Is it possible?
> 
> Regards,
> 
> Dan

cfp:~/src/ruby/ \> cat a.rb  
class Class  
def fattr a, &b  
define\_method(a){ instance\_eval &b }  
end  
end

class C  
fattr(:a){ 40 }  
fattr(:b){ a + 2 }  
end

c = C.new  
p c.b

cfp:~/src/ruby/ \> ruby a.rb  
42

with this approach there is simply no variable to modify - it exists  
only through closure. i know someone could hack in some crazy  
Binding.of\_caller thing to munge the closure, but it would be very  
painful.

kind regards.

-a

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 19, 2007, 6:48pm UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/5 "2007-05-19T18:48:00Z")

</div>

ara.t.howard schrieb:

> c = C.new  
> p c.b
> 
> # =\> 42
> 
> with this approach there is simply no variable to modify - it exists  
> only through closure.

But a method to modify:  
class C  
fattr(:b){ 17 }  
end  
p c.b # =\> 17

Or did I get something wrong?

Sven

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 19, 2007, 8:39pm UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/6 "2007-05-19T20:39:13Z")

</div>

On May 19, 2007, at 10:46 AM, Sven S. wrote:

> > fattr(:b){ a + 2 }  
> > p c.b # =\> 17
> 
> Or did I get something wrong?
> 
> Sven

yes of course. and we also have ‘remove\_const :C’ which allows us to  
replace the class wholesale, and this line of reasoning extends all  
the way up in ruby. still - my approach does, in fact, prevent  
modifying instance vars; the fact that the class itself can stiff be  
modified (by adding methods) may or may not be an issue. perhaps  
enclosed attributes and C.freeze and (class \<\< C;self;end).freeze  
would be sufficient.

-a

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 21, 2007, 10:16am UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/7 "2007-05-21T10:16:29Z")

</div>

ara.t.howard wrote:

> > because you could still get at the instance variable via  
> > Dan  
> > fattr(:a){ 40 }
> 
> with this approach there is simply no variable to modify - it exists  
> only through closure. i know someone could hack in some crazy  
> Binding.of\_caller thing to munge the closure, but it would be very painful.
> 
> kind regards.

Ara, Austin - thanks for the respsonses. Both are interesting  
approaches.

However, I think I’m going to try digging into the opaque objects behind  
the scenes via DL and see if I can’t do something more directly. Perhaps  
I’ll contribute that back to evil.rb. 🙂

Regards,

Dan

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [May 23, 2007, 12:59pm UTC](https://www.ruby-forum.com/t/simulating-single-assignment-in-ruby/104444/8 "2007-05-23T12:59:42Z")

</div>

I think what you want is a constant:

class Foo  
def initialize  
sc.const\_set(:FOO, 42)  
end

def foo  
puts sc::FOO  
end

def sc  
class \<\< self; self; end  
end  
end

Foo.new.foo #=\> 42

(I wish it were possible to use just FOO instead of sc::FOO, but  
constant lookup in ruby is static).

I like Ara’s method too. I wouldn’t have considered it.

Paul
