Reflection, observ(er|able) instance vars?

I generally use define_method only because it works better with the
syntax highlighting of SciTE, and also make the code look a little
unnatural... you also can't pass in real objects to be used by the
method, only things that are stringable.

class_eval %{
  def #{method_name}(*args)
    stuff
  end
}

gets all screwed up (the #{} string is treated as a comment), but

define_method :method_name { |*args|
  stuff
}

works fine. If I was trying to make it run fast, I'd probably be using
class_eval, not define_method.

Evals can be slow, but you're only doing the eval once when it's a
class_eval, and then it's just like any other method, whereas with
define_method you're calling off to the proc object every time, which is
slower than a method call for each and every call.

···

-----Original Message-----
From: Trans [mailto:transfire@gmail.com]
Sent: Saturday, 22 October 2005 10:37 PM
To: ruby-talk ML
Subject: Re: Reflection, observ(er|able) instance vars?

Hugh Sasse wrote:

> This "delivers us from eval" :slight_smile: but does define_method
offer anything
> else over the class_eval %{...} approach? Maybe [only :-)] speed?

Daniel makes some fair points, but there's nothing wrong with
using class_eval here. In fact with eval it's more concise
the resulting code will be faster.

T.

#####################################################################################
This email has been scanned by MailMarshal, an email content filter.
#####################################################################################

I generally use define_method only because it works better with the
syntax highlighting of SciTE, and also make the code look a little
unnatural... you also can't pass in real objects to be used by the

        [...]

works fine. If I was trying to make it run fast, I'd probably be using
class_eval, not define_method.

I couldn't get the class_eval form to work.

Evals can be slow, but you're only doing the eval once when it's a
class_eval, and then it's just like any other method, whereas with
define_method you're calling off to the proc object every time, which is
slower than a method call for each and every call.

I don't know by how much. Anyway, this will be much faster than
doing a full compare each time, and faster than doing a hash each
time, so I don't really need to milk the last drop.

Here is what I ended up with in the end. It does what I want.
If anyone feels like improving on it, you are welcome to do so.

        Thank you
        Hugh

#!/usr/local/bin/ruby -w

···

On Tue, 25 Oct 2005, Daniel Sheppard wrote:
#
# Ruby-Talk:161789 from: "Daniel Sheppard" <daniels@pronto.com.au>
# Provides hashing for an object based on instance vars, and handles
# changes to those vars gracefully.
# The thread begins with Ruby-Talk:161631.
#
# Modified by Hugh Sasse to move it into class Class so attr_hashing
# works like the other attr methods. Also added code so that
# freezing works correctly: Hash works faster with frozen objects.
#
# require 'fasthashequals'
# class Example
# attr_hashing :this, :that, :other
#
# end
#

# For getting an array back as Ruby code.
class Array
  def display
    return "[ "+ map{|x|
      x.inspect
    }.join(', ') + " ]"
  end
end

class Class

    # attr_hashing needs to be a method of class to be useable as
    # the other attr methods are. This method sets up the
    # informtion and methods needed to create the hash from those
    # instance variables.
    def attr_hashing(*arr)
        stararr = arr.flatten
        # puts "stararr is #{stararr.inspect}"
        (stararr).each do |sym|
          attr_reader sym
        end
        hashers = class_eval "@@__hashers ||= "
        hashers.concat(stararr)
        hashers.uniq!
        # puts "@@__hashers = " + hashers.display
        class_eval "@@__hashers = " + hashers.display
        stararr.each do |var|
            define_method(var) {
                instance_variable_get("@#{var}")
            }
            define_method("#{var}=") {|obj|
                instance_variable_set("@#{var}", obj)
                instance_variable_set(:@__equals_hash, nil)
            }
            define_method('eql?') { |other|
                hash === other.hash && hashers.all? { |x|
                    send(x) == other.send(x)
                }
            }
            define_method('hash') {
              # puts "in hash, self is #{self.inspect}"
              @__equals_hash ||= hashers.inject(0) do |s,x|
                  s + instance_variable_get("@#{x}").hash
              end
            }
            # Once we freeze an object we can't update its hash again
            define_method('freeze') {
              hash
              super
            }
        end
    end
end