Simulating single assignment in Ruby

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

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

···

On 5/17/07, Daniel Berger <djberg96@gmail.com> wrote:

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.

--
Austin Ziegler * halostatue@gmail.com * http://www.halostatue.ca/
               * austin@halostatue.ca * You are in a maze of twisty little passages, all alike. // halo • statue
               * austin@zieglers.ca

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

···

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

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

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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

Austin Ziegler schrieb:

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.

class Module
   def erl_accessor(*names)
       [...]
       define_method("#{name}=") { |v|
         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

···

On 5/17/07, Daniel Berger <djberg96@gmail.com> wrote:

ara.t.howard schrieb:

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 # => 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

ara.t.howard wrote:

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

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.

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. :slight_smile:

Regards,

Dan

···

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

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

···

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

ara.t.howard schrieb:

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 # => 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

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama