Plz help with binding

Ruby guru, please help:

I'm creating variable-less storage, wich works fine:

···

#
def arr_fn() ; arr=[] ; lambda{ arr } ; end
fa = arr_fn ; fa[] << 10
fb = arr_fn ; fb[] << 20
p fa[] #=> [10]
p fb[] #=> [20]
# note that fa, fb have different binding for local arr - as expected

Now I'm trying to create instance-var-less storage:
#
class C
    def self.arr_meth( sym )
        arr = []
        define_method sym.to_sym, lambda{ arr }
    end
    arr_meth :arm
end
ca = C.new; ca.arm << 10
cb = C.new; cb.arm << 20
p ca.arm #-> [10, 20]
p cb.arm #-> [10, 20]
p( ca.arm.eql?( cb.arm ) ) #-> true
#
Why ca.arm, cb.arm share same local variable?
Is it bug or feature?

thanks
brs
Sergey

--
Posted via http://www.ruby-forum.com/.

because, in effect, this is what you've done

   class C
     ARR =
     def arm() lambda{ ARM } end
   end

there are a lot of ways to do this but you want something like:

   harp:~ > cat a.rb
   class C
     def self.arr_meth am = nil
       @arr_meths ||=
       @arr_meths << am.to_s if am
       @arr_meths
     end
     arr_meth :arm
     def initialize
       klass = self.class
       singleton_klass = class << self; self; end
       klass.arr_meth.each do |m|
         singleton_klass.module_eval do
           arr =
           define_method m, lambda{ arr }
         end
       end
     end
   end

   ca = C.new; ca.arm << 10
   cb = C.new; cb.arm << 20

   p ca.arm #-> [10]
   p cb.arm #-> [20]
   p( ca.arm.eql?( cb.arm ) ) #-> false

   harp:~ > ruby a.rb
   [10]
   [20]
   false

neat idea btw.

hth.

-a

···

On Thu, 11 May 2006, Sergey Volkov wrote:

Now I'm trying to create instance-var-less storage:
#
class C
   def self.arr_meth( sym )
       arr =
       define_method sym.to_sym, lambda{ arr }
   end
   arr_meth :arm
end
ca = C.new; ca.arm << 10
cb = C.new; cb.arm << 20
p ca.arm #-> [10, 20]
p cb.arm #-> [10, 20]
p( ca.arm.eql?( cb.arm ) ) #-> true
#
Why ca.arm, cb.arm share same local variable?
Is it bug or feature?

--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

an even trickier way:

   harp:~ > cat a.rb
   class C
     def self.arr_meth m
       m = m.to_s
       define_method(m) do
         singleton_class =
           class << self
             self
           end
         singleton_class.module_eval do
           a =
           define_method m, lambda{ a }
         end
         send m # recurse into newly defined method
       end
     end

     arr_meth :arm
   end

   ca = C.new; ca.arm << 10
   cb = C.new; cb.arm << 20

   p ca.arm #-> [10, 20]
   p cb.arm #-> [10, 20]
   p( ca.arm.eql?( cb.arm ) ) #-> true

   harp:~ > ruby a.rb
   [10]
   [20]
   false

-a

···

On Thu, 11 May 2006, Sergey Volkov wrote:

Now I'm trying to create instance-var-less storage:

--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

Sergey Volkov schrieb:

Now I'm trying to create instance-var-less storage:
#
class C
    def self.arr_meth( sym )
        arr =
        define_method sym.to_sym, lambda{ arr }
    end
    arr_meth :arm
end
ca = C.new; ca.arm << 10
cb = C.new; cb.arm << 20
p ca.arm #-> [10, 20]
p cb.arm #-> [10, 20]
p( ca.arm.eql?( cb.arm ) ) #-> true
#
Why ca.arm, cb.arm share same local variable?
Is it bug or feature?

Sergey, your code creates the local variable "arr" and the corresponding lexical closure once for the class "C", so all instances of "C" share the local variable. If you want to have a local variable per instance without using instance variables, you have to define a closure per instance:

  1 class C
  2 def self.arr_meth( sym )
  3 define_method sym.to_sym, lambda{
  4 arr =
  5 class << self; self; end.instance_eval {
  6 define_method sym.to_sym, lambda{ arr }
  7 }
  8 arr
  9 }
10 end
11 arr_meth :arm
12 end

When you call "arr_meth" in line 11, the instance method is defined for class "C", containing the code in lines 4..8. As in your original implementation, this code is shared for all instances of "C".

Now, when you call this method for an instance for the first time, the local variable is created in line 4. Lines 5..7 create the lexical closure for this instance only by defining the method in the singleton class of this instance.

Line 5 gets the singleton class of "self", returns it, and calls "instance_eval" on it, which finally calls "define_method" in line 6. You can't call "define_method" directly on the singleton class, because it's a private method.

Regards,
Pit

Ruby guru, please help:

I'm creating variable-less storage, wich works fine:
#
def arr_fn() ; arr= ; lambda{ arr } ; end
fa = arr_fn ; fa << 10
fb = arr_fn ; fb << 20
p fa #=> [10]
p fb #=> [20]
# note that fa, fb have different binding for local arr - as expected

Now I'm trying to create instance-var-less storage:
#
class C
    def self.arr_meth( sym )
        arr =
        define_method sym.to_sym, lambda{ arr }
    end
    arr_meth :arm
end
ca = C.new; ca.arm << 10
cb = C.new; cb.arm << 20
p ca.arm #-> [10, 20]
p cb.arm #-> [10, 20]
p( ca.arm.eql?( cb.arm ) ) #-> true
#
Why ca.arm, cb.arm share same local variable?
Is it bug or feature?

:slight_smile: You're mad :slight_smile: But I get you... I think.

ca.arm and cb.arm share the same local because they're the same function.

In the first example, you're creating a new lambda, that holds a new
array, with each call to "arr_fn".

In the second example, you're only creating the method "arr" inside the
class B once (with the line "arr_meth : arm"). This method (which is
sitting in the class B, not in each instance of class B - the instances
_share_ it), is what you're later calling, and appending to.

:slight_smile: Totally mad, but thanks, it's a good mind bender.

[I really don't mean to sound insulting, by the way, I think you're
doing something impressively crazy there - it reminds me of "boxes" in
lisp (I think "boxes" is the right term).]

Ara, thanks for your kindness,
but the whole idea was to make it simple, using same approach as with lambda, without need to create any instance variable; in fact I'd like to implement mix-in (Module) with method to be executed in class context as follows:
class A
    include WithLocalsMixIn
    # ?or may be
    # class << self ; include WithLocalsMixIn ; end
    with_locals( :v1, :v2 ){
        #??? initial bind for local vars :v1, :v2
        # sample only, no any practical use
        define_method :get_vars { [v1,v2] }
        define_method :set_vars { |a,b| v1, v2 = a,b }
    }
end
It seems to me this is impossible in Ruby (or inappropriate?)

Thanks, anyway, I got the trick in your solution: we have to create metaclass instance methods during instance initialization.. br-r-r.. I have to practice to start thinking this way :slight_smile:
And I still do not understand why def arr_fn creates binding, while def self.arr_meth does not.
And why lambda does not work here:

···

#
class C
    def self.arr_meth( sym )
        lambda{
            arr =
            define_method sym.to_sym, lambda{ arr }
        }
    end
    arr_meth :arm
end
#
my Lisp experience does help, Ruby is not functional enough and I'm missing Lisp macros :frowning:

---

Just received your second message with 'trickier way': now I'm wondering, why trickier way is required, when simple lexical closure works perfectly and, as I understand, it's available in Ruby. Is Ruby closure true closure? Or does instance context ruins it? Or I misunderstand it totally?

I like Ruby very much, but so far I fail to understand very fundamental language features :frowning:
like this, for ex:
#
class StrWithPref < String ; def pref(n) self[0..n] end end
p StrWithPref.new("ABCD").pref(2).class
#
prints StrWithPref, not String as I expected;

well, as for now, I'm still leaning Ruby (and enjoy it a lot);
thanks to all for great Ruby community,
cheers
Sergey

----- Original Message ----- From: <ara.t.howard@noaa.gov>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, May 11, 2006 1:55 AM
Subject: Re: plz help with binding

On Thu, 11 May 2006, Sergey Volkov wrote:

Now I'm trying to create instance-var-less storage:
#
class C
   def self.arr_meth( sym )
       arr =
       define_method sym.to_sym, lambda{ arr }
   end
   arr_meth :arm
end
ca = C.new; ca.arm << 10
cb = C.new; cb.arm << 20
p ca.arm #-> [10, 20]
p cb.arm #-> [10, 20]
p( ca.arm.eql?( cb.arm ) ) #-> true
#
Why ca.arm, cb.arm share same local variable?
Is it bug or feature?

because, in effect, this is what you've done

  class C
    ARR =
    def arm() lambda{ ARM } end
  end

there are a lot of ways to do this but you want something like:

  harp:~ > cat a.rb
  class C
    def self.arr_meth am = nil
      @arr_meths ||=
      @arr_meths << am.to_s if am
      @arr_meths
    end
    arr_meth :arm
    def initialize
      klass = self.class
      singleton_klass = class << self; self; end
      klass.arr_meth.each do |m|
        singleton_klass.module_eval do
          arr =
          define_method m, lambda{ arr }
        end
      end
    end
  end

  ca = C.new; ca.arm << 10
  cb = C.new; cb.arm << 20

  p ca.arm #-> [10]
  p cb.arm #-> [20]
  p( ca.arm.eql?( cb.arm ) ) #-> false

  harp:~ > ruby a.rb
  [10]
  [20]
  false

neat idea btw.

hth.

-a
--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

This is cool!
But not for average (read big enterprise) level programmer :frowning:
How can I follow 'keep it simple, stupid!' approach with Ruby metaprogramming?
How many Ruby programmers can reproduce this code with easy?
Can such code code be supported in production environment?

I'm not asking, I'm crying!
I'd like to ask Matz: give me real lexical closure and clean up meta class mess, please!!!

Or should we admit, that Ruby metaprogramming is for real programmers only?
Or I'm just plain stupid?

Please advise;
thanks
bests
Sergey

···

----- Original Message ----- From: <ara.t.howard@noaa.gov>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, May 11, 2006 2:11 AM
Subject: Re: plz help with binding

On Thu, 11 May 2006, Sergey Volkov wrote:

Now I'm trying to create instance-var-less storage:

an even trickier way:

  harp:~ > cat a.rb
  class C
    def self.arr_meth m
      m = m.to_s
      define_method(m) do
        singleton_class =
          class << self
            self
          end
        singleton_class.module_eval do
          a =
          define_method m, lambda{ a }
        end
        send m # recurse into newly defined method
      end
    end

    arr_meth :arm
  end

  ca = C.new; ca.arm << 10
  cb = C.new; cb.arm << 20

  p ca.arm #-> [10, 20]
  p cb.arm #-> [10, 20]
  p( ca.arm.eql?( cb.arm ) ) #-> true

  harp:~ > ruby a.rb
  [10]
  [20]
  false

-a
--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

Sorry, guys,
I must admit - I was not right about Ruby closures;
most probably about metaprogramming neither,
so, please disregard my previous message;

closures work in Ruby perfectly, my mistake was that arr_meth was executed only once inside class definition:

···

#
class C
    def self.arr_meth( sym )
        arr =
        define_method sym.to_sym, lambda{ arr }
    end
    arr_meth :arm
end
#
closure was created, but it was then shared between all class instances, so Ara was absolutely right - we have to create new closure for each individual instance, and this can not be implemented on class level (no instances yet!);

I still do not want to modify class code to add instance_var-less storage, so at this moment I have implemented external function to extend class with new method (thanks, Ara!):
#!/bin/ruby
module M
    def self.add_loc obj, name, ini=
        skl = class << obj ; self ; end
        skl.module_eval{
           v = ini
           define_method name.to_sym, lambda{ v }
        }
    end
end
#
ca = Object.new
M.add_loc ca,:pocket; ca.pocket << 10
M.add_loc ca,:bag; ca.bag << :book
#
cb = Object.new
M.add_loc cb,:pocket; cb.pocket << 20
M.add_loc cb,:bag; cb.bag << :apple
#
p [ca.pocket, ca.bag]
p [cb.pocket, cb.bag]
---------- Capture Output ----------
[[10], [:book]]
[[20], [:apple]]

Hidden instance slots created! In this example they contain array, but accessors can be implemented without any problem.
Any ideas about better API?
thanks
regards
Sergey
--
oh - please do not forget to be kind!

----- Original Message ----- From: "Sergey Volkov" <gm.vlkv@gmail.com>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, May 11, 2006 3:39 AM
Subject: Re: plz help with binding

This is cool!
But not for average (read big enterprise) level programmer :frowning:
How can I follow 'keep it simple, stupid!' approach with Ruby metaprogramming?
How many Ruby programmers can reproduce this code with easy?
Can such code code be supported in production environment?

I'm not asking, I'm crying!
I'd like to ask Matz: give me real lexical closure and clean up meta class mess, please!!!

Or should we admit, that Ruby metaprogramming is for real programmers only?
Or I'm just plain stupid?

Please advise;
thanks
bests
Sergey

----- Original Message ----- From: <ara.t.howard@noaa.gov>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, May 11, 2006 2:11 AM
Subject: Re: plz help with binding

On Thu, 11 May 2006, Sergey Volkov wrote:

Now I'm trying to create instance-var-less storage:

an even trickier way:

  harp:~ > cat a.rb
  class C
    def self.arr_meth m
      m = m.to_s
      define_method(m) do
        singleton_class =
          class << self
            self
          end
        singleton_class.module_eval do
          a =
          define_method m, lambda{ a }
        end
        send m # recurse into newly defined method
      end
    end

    arr_meth :arm
  end

  ca = C.new; ca.arm << 10
  cb = C.new; cb.arm << 20

  p ca.arm #-> [10, 20]
  p cb.arm #-> [10, 20]
  p( ca.arm.eql?( cb.arm ) ) #-> true

  harp:~ > ruby a.rb
  [10]
  [20]
  false

-a
--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

thanks all for your patience,
Ara, Pit for your help;

here is my solution, if you are interested,
now you can get rid of instance variables in your Ruby code :slight_smile:

···

#
module M
    def add_loc name, reader_only=false, ini=nil
        skl = class << self ; self ; end
        skl.module_eval{
           v = ini
           define_method name.to_sym, lambda{ v }
           define_method "#{name}=".to_sym, lambda{ |a| v = a } unless reader_only
        }
    end
end
#
class CA ; include M ; end
ca = CA.new
ca.add_loc :pocket, true, # reader only
ca.add_loc :bag
ca.pocket << 10
ca.bag = :book
#
class CB ; include M ; end
cb = CB.new
cb.add_loc :address_book, true, {}; cb.address_book["me"] = "my address"
cb.add_loc :bag; cb.bag = :apple
#
p [ca.pocket, ca.bag]
p [cb.address_book, cb.bag]
#
---------- Capture Output ----------
[[10], :book]
[{"me"=>"my address"}, :apple]

regards
Sergey
--
There are 10 kinds of people in the world; those who know binary, and those who don't.

----- Original Message ----- From: "Sergey Volkov" <gm.vlkv@gmail.com>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, May 11, 2006 4:33 AM
Subject: Re: plz help with binding

Sorry, guys,
I must admit - I was not right about Ruby closures;
most probably about metaprogramming neither,
so, please disregard my previous message;

closures work in Ruby perfectly, my mistake was that arr_meth was executed only once inside class definition:
#
class C
   def self.arr_meth( sym )
       arr =
       define_method sym.to_sym, lambda{ arr }
   end
   arr_meth :arm
end
#
closure was created, but it was then shared between all class instances, so Ara was absolutely right - we have to create new closure for each individual instance, and this can not be implemented on class level (no instances yet!);

I still do not want to modify class code to add instance_var-less storage, so at this moment I have implemented external function to extend class with new method (thanks, Ara!):
#!/bin/ruby
module M
   def self.add_loc obj, name, ini=
       skl = class << obj ; self ; end
       skl.module_eval{
          v = ini
          define_method name.to_sym, lambda{ v }
       }
   end
end
#
ca = Object.new
M.add_loc ca,:pocket; ca.pocket << 10
M.add_loc ca,:bag; ca.bag << :book
#
cb = Object.new
M.add_loc cb,:pocket; cb.pocket << 20
M.add_loc cb,:bag; cb.bag << :apple
#
p [ca.pocket, ca.bag]
p [cb.pocket, cb.bag]
---------- Capture Output ----------
[[10], [:book]]
[[20], [:apple]]

Hidden instance slots created! In this example they contain array, but accessors can be implemented without any problem.
Any ideas about better API?
thanks
regards
Sergey
--
oh - please do not forget to be kind!

----- Original Message ----- From: "Sergey Volkov" <gm.vlkv@gmail.com>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, May 11, 2006 3:39 AM
Subject: Re: plz help with binding

This is cool!
But not for average (read big enterprise) level programmer :frowning:
How can I follow 'keep it simple, stupid!' approach with Ruby metaprogramming?
How many Ruby programmers can reproduce this code with easy?
Can such code code be supported in production environment?

I'm not asking, I'm crying!
I'd like to ask Matz: give me real lexical closure and clean up meta class mess, please!!!

Or should we admit, that Ruby metaprogramming is for real programmers only?
Or I'm just plain stupid?

Please advise;
thanks
bests
Sergey

----- Original Message ----- From: <ara.t.howard@noaa.gov>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Thursday, May 11, 2006 2:11 AM
Subject: Re: plz help with binding

On Thu, 11 May 2006, Sergey Volkov wrote:

Now I'm trying to create instance-var-less storage:

an even trickier way:

  harp:~ > cat a.rb
  class C
    def self.arr_meth m
      m = m.to_s
      define_method(m) do
        singleton_class =
          class << self
            self
          end
        singleton_class.module_eval do
          a =
          define_method m, lambda{ a }
        end
        send m # recurse into newly defined method
      end
    end

    arr_meth :arm
  end

  ca = C.new; ca.arm << 10
  cb = C.new; cb.arm << 20

  p ca.arm #-> [10, 20]
  p cb.arm #-> [10, 20]
  p( ca.arm.eql?( cb.arm ) ) #-> true

  harp:~ > ruby a.rb
  [10]
  [20]
  false

-a
--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

Sergey Volkov schrieb:

closure was created, but it was then shared between all class instances, so Ara was absolutely right - we have to create new closure for each individual instance, and this can not be implemented on class level (no instances yet!);

Sergey, maybe I don't understand what you mean by "implemented on class level", but as I've tried to show you with the code in my previous post you *can* implement such local variables at the class level. Here's the output, just in case you haven't tried:

   class C
     ...
     arr_meth :arm
   end

   ca = C.new; ca.arm << 10
   cb = C.new; cb.arm << 20

   p ca.arm # => [10]
   p cb.arm # => [20]
   p ca.arm.eql?( cb.arm ) # => false

Regards,
Pit

closure was created, but it was then shared between all class instances, so
Ara was absolutely right - we have to create new closure for each individual
instance, and this can not be implemented on class level (no instances
yet!);

yes exactly - you must defer creation of the closure somehow. it must be an
'instance closure' instead of an 'instance variable' - we can get away from
doing something at the instance level otherwise they all share the same
'thing' :wink:

I still do not want to modify class code to add instance_var-less storage,
so at this moment I have implemented external function to extend class with
new method (thanks, Ara!):

#!/bin/ruby
module M
  def self.add_loc obj, name, ini=
      skl = class << obj ; self ; end
      skl.module_eval{
         v = ini
         define_method name.to_sym, lambda{ v }
      }
  end
end

yes, you are getting it - must be the lisp background, it took me a long time
to get this stuff!

Any ideas about better API?

use keywords - default paramerters are pure evil :

   some_method(42,true,true,true,false,2) #=> YUK

vs

   some_method 42 :async => true, :block_size #=> 2 # AHHH :wink:

so, for instance:

     harp:~ > cat a.rb
     class Object
       def singleton_class &b
         sc =
           class << self
             self
           end
         sc.module_eval &b if b
         sc
       end
     end

     class Module
       def vattr m, opts = {}, &b
         m = m.to_s

         reader = opts['reader'] || opts[:reader]
         writer = opts['writer'] || opts[:writer]
         query = opts['query'] || opts[:query]

         accessor = ![reader, writer].any?

         reader = "#{ m }" if reader or accessor
         writer = "#{ m }=" if writer or accessor
         query = "#{ m }?" if query or accessor

         define_method(reader) do
           singleton_class do
             val = b.call if b
             define_method reader, lambda{ val }
           end
           send reader
         end if reader

         define_method(writer) do |val|
           singleton_class do
             vattr(reader){ val }
           end
           send reader
         end if writer

         define_method(query) do
           not not send reader
         end if query

         [reader, writer, query]
       end
       def vattr_r m, opts = {}, &b
         opts.update 'reader' => true
         vattr m, opts, &b
       end
       def vattr_w m, opts = {}, &b
         opts.update 'writer' => true
         vattr m, opts, &b
       end
     end

     class C
       vattr('va'){ }
     end

     ca = C.new; ca.va << 10
     cb = C.new; cb.va << 20

     p ca.va #-> [10]
     p cb.va #-> [10]

     ca.va = {}
     cb.va = {}

     ca.va.update 'k' => 4
     cb.va.update 'k' => 2

     p ca.va? #-> true
     p ca.va #-> {"k"=>4}

     p cb.va? #-> true
     p cb.va #-> {"k"=>2}

     harp:~ > ruby a.rb
     [10]
     [20]
     true
     {"k"=>4}
     true
     {"k"=>2}

regards.

-a

···

On Thu, 11 May 2006, Sergey Volkov wrote:
--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

thanks all for your patience,
Ara, Pit for your help;

here is my solution, if you are interested,
now you can get rid of instance variables in your Ruby code :slight_smile:

:slight_smile: Doesn't this still suffer from the previous problem though? The
"variable" is stored per class, rather than per instance?

Do you mean singleton class?
If so, then it's the same as per instance.
But I need even more - variable stored per add_loc call, I thought I made it, here is how:

v = ini is executed every time add_loc is called, so every time new binding for local variable v is created, which is referenced in accessor methods;
I can move assignment out of module_eval scope, result is the same:

···

----- Original Message ----- From: <benjohn@fysh.org>
Sent: Thursday, May 11, 2006 6:08 AM
Subject: Re: plz help with binding

here is my solution, if you are interested,
now you can get rid of instance variables in your Ruby code :slight_smile:

:slight_smile: Doesn't this still suffer from the previous problem though? The
"variable" is stored per class, rather than per instance?

#
module M
    def add_loc name, reader_only=false, ini=nil
        skl = class << self ; self ; end
        v = ini # create new local variable binding
        skl.module_eval{
           define_method name.to_sym, lambda{ v } # reader
           define_method "#{name}=".to_sym, lambda{ |a| v = a } unless reader_only
        }
    end
end
#
class CC ; include M ; end
ca = CC.new
ca.add_loc :pocket, true, # array, reader only
ca.add_loc :bag
ca.pocket << 10
ca.bag = :book
#
cb = CC.new
cb.add_loc :address_book, true, {} # hash, reader only
cb.add_loc :bag
cb.address_book["me"] = "my address"
cb.bag = :apple
#
p [ca.pocket, ca.bag]
p [cb.address_book, cb.bag]
---------- Capture Output ----------
[[10], :book]
[{"me"=>"my address"}, :apple]

Terminated with exit code 0.

what am I missing here?