Simulating single assignment in Ruby

Discussion in 'Ruby' started by Daniel Berger, May 18, 2007.

  1. 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
    Daniel Berger, May 18, 2007
    #1
    1. Advertising

  2. On 5/17/07, Daniel Berger <> 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.


    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
    --
    Austin Ziegler * * http://www.halostatue.ca/
    * * http://www.halostatue.ca/feed/
    *
    Austin Ziegler, May 18, 2007
    #2
    1. Advertising

  3. Daniel Berger

    Sven Suska Guest

    Austin Ziegler schrieb:

    > On 5/17/07, Daniel Berger <> 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.

    >
    > 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
    Sven Suska, May 18, 2007
    #3
  4. Daniel Berger

    ara.t.howard Guest

    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
    >


    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
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
    ara.t.howard, May 19, 2007
    #4
  5. Daniel Berger

    Sven Suska Guest

    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
    Sven Suska, May 19, 2007
    #5
  6. Daniel Berger

    ara.t.howard Guest

    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
    >


    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
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
    ara.t.howard, May 19, 2007
    #6
  7. ara.t.howard wrote:
    >
    > 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
    >>

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

    Regards,

    Dan
    Daniel Berger, May 21, 2007
    #7
  8. Daniel Berger

    Paul Brannan Guest

    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
    Paul Brannan, May 23, 2007
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nagy
    Replies:
    36
    Views:
    980
    Terry Reedy
    Jul 20, 2006
  2. Chris
    Replies:
    34
    Views:
    1,483
  3. matt neuburg
    Replies:
    7
    Views:
    101
    matt neuburg
    May 8, 2008
  4. Replies:
    34
    Views:
    335
    John Bokma
    Mar 8, 2006
  5. bernd
    Replies:
    0
    Views:
    617
    bernd
    Apr 24, 2012
Loading...

Share This Page