Automatically call function on attribute set

I have a class that represents an airplane. This class has a bunch of data
members: x/y/z positions, x/y/z velocities, pitches, rolls, etc. What I did
is let the user configure what different attributes the airplane had in a
YAML config file, then have the airplane class read in that file and setup
attr_accessors for each attribute in the file.

I have another object (call it airplane_drawing) that is responsible for
drawing this airplane on the screen. It needs to have access to some of the
attributes of the airplane, and it needs have some of its own attributes
changed whenever airplane's attributes changes.

What is the best way to get airplane_drawing to be notified whenever some
attribute of airplane is changed? Should I have a thread (or similar) that
checks the airplane object to see if anything's changed?

I hope I've explained this well enough for people to understand... I feel
like this is a fairly common thing to do, but I'm not sure of the best way
to do it.

Thanks,
Joe

check out

   observer.rb in ruby's lib dir.

it has an example in it.

-a

···

On Wed, 10 Nov 2004, Joe Laughlin wrote:

I have a class that represents an airplane. This class has a bunch of data
members: x/y/z positions, x/y/z velocities, pitches, rolls, etc. What I did
is let the user configure what different attributes the airplane had in a
YAML config file, then have the airplane class read in that file and setup
attr_accessors for each attribute in the file.

I have another object (call it airplane_drawing) that is responsible for
drawing this airplane on the screen. It needs to have access to some of the
attributes of the airplane, and it needs have some of its own attributes
changed whenever airplane's attributes changes.

What is the best way to get airplane_drawing to be notified whenever some
attribute of airplane is changed? Should I have a thread (or similar) that
checks the airplane object to see if anything's changed?

I hope I've explained this well enough for people to understand... I feel
like this is a fairly common thing to do, but I'm not sure of the best way
to do it.

Thanks,
Joe

--

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
When you do something, you should burn yourself completely, like a good
bonfire, leaving no trace of yourself. --Shunryu Suzuki

===============================================================================

You should use an Observer.

  require 'observer'

  class Airplane
    include Observable

    def initialize
      @x = 0
    end

    def fly
      # airplane changes it's coordinate
      @x += 10

      changed
      notify_observers(self)
    end
  end

  class AirplaneDrawing
    def update(obj)
      # ...
    end
  end

  airbus = Airplane.new
  drawing = AirplaneDrawing.new
  airbus.add_observer(drawing)
  airbus.fly

Regards,

  Michael

···

On Thu, Nov 11, 2004 at 03:13:30AM +0900, Joe Laughlin wrote:

I have a class that represents an airplane. This class has a bunch of data
members: x/y/z positions, x/y/z velocities, pitches, rolls, etc. What I did
is let the user configure what different attributes the airplane had in a
YAML config file, then have the airplane class read in that file and setup
attr_accessors for each attribute in the file.

I have another object (call it airplane_drawing) that is responsible for
drawing this airplane on the screen. It needs to have access to some of the
attributes of the airplane, and it needs have some of its own attributes
changed whenever airplane's attributes changes.

What is the best way to get airplane_drawing to be notified whenever some
attribute of airplane is changed? Should I have a thread (or similar) that
checks the airplane object to see if anything's changed?

Joe Laughlin wrote:

I have a class that represents an airplane. This class has a bunch of data
members: x/y/z positions, x/y/z velocities, pitches, rolls, etc. What I did
is let the user configure what different attributes the airplane had in a
YAML config file, then have the airplane class read in that file and setup
attr_accessors for each attribute in the file.

I have another object (call it airplane_drawing) that is responsible for
drawing this airplane on the screen. It needs to have access to some of the
attributes of the airplane, and it needs have some of its own attributes
changed whenever airplane's attributes changes.

What is the best way to get airplane_drawing to be notified whenever some
attribute of airplane is changed? Should I have a thread (or similar) that
checks the airplane object to see if anything's changed?

I hope I've explained this well enough for people to understand... I feel
like this is a fairly common thing to do, but I'm not sure of the best way
to do it.

Another approach is the observable lib on RAA (http://raa.ruby-lang.org/list.rhtml?name=observable\).

   require 'observable'

   class Airplane
     extend Observable

     observable :x, :y, :z

     def initialize(x = 0, y = 0, z = 0)
       @x, @y, @z = x, y, z
     end

     def fly
       self.x += 1 # don't use @x=, or else no notification
     end
   end

   class Drawing
     def initialize(airplane)
       airplane.when_x do
         puts "moving in x dimension to #{airplane.x}"
       end
     end
   end

   airplane = Airplane.new
   drawing = Drawing.new(airplane) # ==> moving in x dimension to 0
   airplane.fly # ==> moving in x dimension to 1
   airplane.fly # ==> moving in x dimension to 2

The observer.rb in the standard library is better if you want more control over sending the notification. For example, if x,y,z all change, but you only want to send the notification once for all three. (Or you could use an attribute that contains the whole x,y,z point, and make that observable.)

Joe Laughlin wrote:

I have a class that represents an airplane. This class
has a bunch of data members: x/y/z positions, x/y/z
velocities, pitches, rolls, etc. What I did is let the
user configure what different attributes the airplane had
in a YAML config file, then have the airplane class read
in that file and setup attr_accessors for each attribute
in the file.

I have another object (call it airplane_drawing) that is
responsible for drawing this airplane on the screen. It
needs to have access to some of the attributes of the
airplane, and it needs have some of its own attributes
changed whenever airplane's attributes changes.

What is the best way to get airplane_drawing to be
notified whenever some attribute of airplane is changed?
Should I have a thread (or similar) that checks the
airplane object to see if anything's changed?

I hope I've explained this well enough for people to
understand... I feel like this is a fairly common thing
to do, but I'm not sure of the best way to do it.

Thanks,
Joe

Aha! Thanks for the response you guys. I knew that there was a pattern
that would help me, but I just couldn't think of it.

Joel VanderWerf wrote:

Joe Laughlin wrote:

I have a class that represents an airplane. This class
has a bunch of data members: x/y/z positions, x/y/z
velocities, pitches, rolls, etc. What I did is let the
user configure what different attributes the airplane
had in a YAML config file, then have the airplane class
read in that file and setup attr_accessors for each
attribute in the file.

I have another object (call it airplane_drawing) that is
responsible for drawing this airplane on the screen. It
needs to have access to some of the attributes of the
airplane, and it needs have some of its own attributes
changed whenever airplane's attributes changes.

What is the best way to get airplane_drawing to be
notified whenever some attribute of airplane is changed?
Should I have a thread (or similar) that checks the
airplane object to see if anything's changed?

I hope I've explained this well enough for people to
understand... I feel like this is a fairly common thing
to do, but I'm not sure of the best way to do it.

Another approach is the observable lib on RAA
(http://raa.ruby-lang.org/list.rhtml?name=observable\).

   require 'observable'

   class Airplane
     extend Observable

     observable :x, :y, :z

     def initialize(x = 0, y = 0, z = 0)
       @x, @y, @z = x, y, z
     end

     def fly
       self.x += 1 # don't use @x=, or else no
     notification end
   end

What is the difference between self.x and @x?

Thanks,
Joe

self.x, sends either the :x or :x= method to self, depending if it's
an lvalue or rvalue respectively. @x just reads/writes to the instance
variable directly. If you're just using attr_accessor :x, they're the
same thing, but if you have, for instance:

class Foo
   def bar
      raise "@bar and @baz out of sync" unless @bar == @baz
      @bar
   end
   def bar=( new_bar )
      puts "setting @bar and @baz"
      @bar = @baz = new_bar
   end
   def test1
      self.bar = "test1"
   end
   def test2
      @bar = "test2"
   end
end

foo = Foo.new
foo.bar = "test"
# => setting @bar and @baz

puts foo.bar
# => test

foo.test1
# => setting @bar and @baz

puts foo.bar
# => test1

foo.test2
puts foo.bar
# RuntimeError: @bar and @baz out of sync

Using self.bar= keeps @bar and @baz in sync, while setting @bar
directly doesn't update @baz. Generally, if you have non-trivial
accessors for instance variables, you should use them even inside the
object rather than accessing the instance variables directly. I
usually use them even if the accessor is trivial, so that if the
accessor becomes non-trivial later I don't have to go find and fix all
the places where the instance variables are currently accessed
directly.

Jacob Fugal

···

On Fri, 12 Nov 2004 04:13:30 +0900, Joe Van Dyk <joe.vandyk@boeing.com> wrote:

What is the difference between self.x and @x?

Joe Van Dyk wrote:

Joel VanderWerf wrote:

    def fly
      self.x += 1 # don't use @x=, or else no
    notification end
  end

What is the difference between self.x and @x?

In ruby, assigning to an instance variable @x like

   @x += 1

does not invoke any methods (except the + method of the Integer class,
in this case). So there's no way for the Airplane class to detect the
assignment and (in this case) notify observers.

By contrast, the code

   self.x += 1

forces a call to the method "x=", which has been defined by "observable
:x" to both set the value of @x and to notify observers.

And just for completeness, the code

   x += 1

can only assign to a local variable, even if "x=" has been defined as a
method.

"Joel VanderWerf" <vjoel@PATH.Berkeley.EDU> wrote in message
news:4193C096.7070007@path.berkeley.edu...

Joe Van Dyk wrote:
> Joel VanderWerf wrote:
>
>> def fly
>> self.x += 1 # don't use @x=, or else no
>> notification end
>> end
>>
>
>
> What is the difference between self.x and @x?

In ruby, assigning to an instance variable @x like

   @x += 1

does not invoke any methods (except the + method of the Integer class,
in this case). So there's no way for the Airplane class to detect the
assignment and (in this case) notify observers.

By contrast, the code

   self.x += 1

forces a call to the method "x=", which has been defined by "observable
:x" to both set the value of @x and to notify observers.

And just for completeness, the code

   x += 1

can only assign to a local variable, even if "x=" has been defined as a
method.

Ok. In general, it's best to use self.x as opposed to @x?

Joe Van Dyk wrote:

"Joel VanderWerf" <vjoel@PATH.Berkeley.EDU> wrote in message
news:4193C096.7070007@path.berkeley.edu...

Joe Van Dyk wrote:

Joel VanderWerf wrote:

   def fly
     self.x += 1 # don't use @x=, or else no
   notification end
end

What is the difference between self.x and @x?

In ruby, assigning to an instance variable @x like

  @x += 1

does not invoke any methods (except the + method of the Integer class,
in this case). So there's no way for the Airplane class to detect the
assignment and (in this case) notify observers.

By contrast, the code

  self.x += 1

forces a call to the method "x=", which has been defined by "observable
:x" to both set the value of @x and to notify observers.

And just for completeness, the code

  x += 1

can only assign to a local variable, even if "x=" has been defined as a
method.

Ok. In general, it's best to use self.x as opposed to @x?

Depends. I tend to use @x as rarely as possible, so that subclasses can, if necessary, define methods that get/set the value in some other way. Or if I later decide that the class itself needs to do something else and not just go directly to the instance variable (for instance, logging code). But accessing @x is faster than sending the #x method to self.