[newbie] The Duck Problem, or accessing one instance var from another

Discussion in 'Ruby' started by Vladimir Agafonkin, Jan 24, 2006.

  1. Hi!

    What is the best way to access class' instance variables from a method
    of another instance variable of the same class that is a class itself?
    :)

    OK, Let's say I have Duck class with an instance variable
    @quack_behaviour of QuackBehaviour class inside. Duck#quack method
    calls one of the QuackBehaviour methods, and I want to access some of
    the intance variables (say, @name) of the caller Duck object from that
    method.

    One way is to set an attr_accessor :name (or use instance_variable_get)
    and pass "self" as a parameter to the @quack_behaviour method. But it
    seems for me that it is not the most appropriate way of doing this. Or
    is it?
     
    Vladimir Agafonkin, Jan 24, 2006
    #1
    1. Advertising

  2. Vladimir Agafonkin

    Guest

    Re: [newbie] The Duck Problem, or accessing one instance var fromanother

    On Mon, 23 Jan 2006, Vladimir Agafonkin wrote:

    > What is the best way to access class' instance variables from a method of
    > another instance variable of the same class that is a class itself? :)
    >
    > OK, Let's say I have Duck class with an instance variable @quack_behaviour
    > of QuackBehaviour class inside. Duck#quack method calls one of the
    > QuackBehaviour methods, and I want to access some of the intance variables
    > (say, @name) of the caller Duck object from that method.
    >
    > One way is to set an attr_accessor :name (or use instance_variable_get) and
    > pass "self" as a parameter to the @quack_behaviour method. But it seems for
    > me that it is not the most appropriate way of doing this. Or is it?



    harp:~ > cat a.rb
    class Duck
    attr_accessor "quack_behaviour"
    def initialize(quack_behaviour) self.quack_behaviour = quack_behaviour::new(self) end
    def quack() quack_behaviour.quack end
    def name() "duck" end
    end
    class QuackBehaviour
    def self::duck_attr a
    module_eval <<-code
    def #{ a }() duck.#{ a } end
    def #{ a }=(val) duck.#{ a }=val end
    code
    end
    attr_accessor "duck"
    duck_attr "name"
    def initialize(duck) self.duck = duck end
    def quack() p name end
    end

    duck = Duck::new(QuackBehaviour)
    duck.quack

    harp:~ > ruby a.rb
    "duck"

    is one way. if you need to dynamically change the quack_behaviour object i'd
    make a method that pushed/popped/ensured a QuackBehaviour object was in effect
    - but having the QuackBehaviour object have a reference to their parent, if
    possible, simplifies things.

    regards.

    -a
    --
    strong and healthy, who thinks of sickness until it strikes like lightning?
    preoccupied with the world, who thinks of death, until it arrives like
    thunder? -- milarepa
     
    , Jan 24, 2006
    #2
    1. Advertising

  3. Vladimir Agafonkin wrote:
    > Hi!
    >
    > What is the best way to access class' instance variables from a method
    > of another instance variable of the same class that is a class itself?
    > :)
    >
    > OK, Let's say I have Duck class with an instance variable
    > @quack_behaviour of QuackBehaviour class inside. Duck#quack method
    > calls one of the QuackBehaviour methods, and I want to access some of
    > the intance variables (say, @name) of the caller Duck object from that
    > method.
    >
    > One way is to set an attr_accessor :name (or use
    > instance_variable_get) and pass "self" as a parameter to the
    > @quack_behaviour method. But it seems for me that it is not the most
    > appropriate way of doing this. Or is it?


    Sounds like an application of state or strategy pattern. I posted some
    example code a few days / weeks ago. Basically, if your two classes are
    rather tightly coupled you can have each instance point to the other.
    That way both can access methods on the other instance. The only ugly
    thing being that you have to manually keep references in sync.

    HTH

    robert
     
    Robert Klemme, Jan 24, 2006
    #3
  4. On 24/01/06, Vladimir Agafonkin <> wrote:
    > What is the best way to access class' instance variables from a method
    > of another instance variable of the same class that is a class itself?
    > :)
    >
    > OK, Let's say I have Duck class with an instance variable
    > @quack_behaviour of QuackBehaviour class inside. Duck#quack method
    > calls one of the QuackBehaviour methods, and I want to access some of
    > the intance variables (say, @name) of the caller Duck object from that
    > method.
    >
    > One way is to set an attr_accessor :name (or use
    > instance_variable_get) and pass "self" as a parameter to the
    > @quack_behaviour method. But it seems for me that it is not the most
    > appropriate way of doing this. Or is it?


    Huh?

    class QuackBehaviour
    def loudly
    =09 "LOUDLY"
    =09end
    end

    class Duck
    def initialize
    =09 @quack_behaviour =3D QuackBehaviour.new
    =09 @name =3D "Daffy"
    =09end

    def quack
    =09 @quack_behaviour.loudly
    =09end
    end

    There's nothing in the above that even remotely allows for
    QuackBehaviour#loudly to reach inside of the Duck instance. You will, as
    you said, need to either register the duck instance or pass +self+ as a
    parameter.

    -austin
    --
    Austin Ziegler *
    * Alternate:
     
    Austin Ziegler, Jan 24, 2006
    #4
  5. Re: The Duck Problem, or accessing one instance var from another

    Thanks! I will keep that in mind. Though I think that it complicates
    things a lot in exchange for using just "attr" instead of, say,
    "@obj.attr" for accessign an attribute.
     
    Vladimir Agafonkin, Jan 24, 2006
    #5
  6. Re: The Duck Problem, or accessing one instance var from another

    Thanks, Robert. You're right, a strategy pattern (I just started
    reading "Head First Design Patterns" of O'Reilly). What do you mean by
    manually keep references synchronized?

    I implented my solution with cross-references, and it seems quite
    automated (though there's still room for improvement). Here's what I
    came with (in short):

    #================================================
    class Duck
    attr_reader :name

    def initialize(name, fly_behaviour=:fly_with_wings,
    quack_behaviour=:quack)
    @fly_behaviour = FlyBehaviour.new(self, fly_behaviour)
    @quack_behaviour = QuackBehaviour.new(self, quack_behaviour)
    @name = name
    end

    def fly
    @fly_behaviour.perform
    end

    def quack
    @quack_behaviour.perform
    end
    end

    class Behaviour
    def initialize(object, behaviour);
    @obj = object;
    @behaviour = behaviour;
    end

    def perform
    send(@behaviour)
    end

    def self.list;
    self.protected_instance_methods
    end
    end

    class FlyBehaviour < Behaviour
    protected
    def fly_with_wings
    puts "#{@obj.name} is flying!"
    end

    def do_not_fly
    puts "#{@obj.name} can't fly. :-("
    end
    end

    class QuackBehaviour < Behaviour
    protected
    def quack
    puts "#{@obj.name} is quacking! Quack!!"
    end

    def squeak
    puts "#{@obj.name} is quacking! Squeak!!!"
    end
    end

    class RubberDuck < Duck
    def initialize(name)
    super(name,:do_not_fly,:squeak)
    end
    end

    ducks = []
    ducks << Duck.new("George")
    ducks << RubberDuck.new("Wacky")

    ducks.each do |duck|
    duck.quack
    duck.fly
    end

    p QuackBehaviour.list
    #================================================

    The next big thing would be to implement generating behaviour-related
    methods in the Duck class on the fly. Through method_missing, maybe?
    And, of course, behaviour instance variables too. That seems a bit
    harder to do, but I'm a programming newbie after all! :) The perfect
    use of the solution would look like:

    usually_able_to :fly, :quack, :swim

    that looks similiar to Rails has_many and belongs_too. Maybe I need to
    check it's code for an idea.

    And there's another question: how to make all methods defined in
    Behaviour children protected? The code would be more attractive if I
    hadn't to write "protected" in the beginning of each behaviour child.
     
    Vladimir Agafonkin, Jan 24, 2006
    #6
  7. Re: The Duck Problem, or accessing one instance var from another

    Thanks, Robert. You're right, a strategy pattern (I just started
    reading "Head First Design Patterns" of O'Reilly). What do you mean by
    manually keep references synchronized?

    I implented my solution with cross-references, and it seems quite
    automated (though there's still room for improvement). Here's what I
    came with (in short):

    #================================================
    class Duck
    attr_reader :name

    def initialize(name, fly_behaviour=:fly_with_wings,
    quack_behaviour=:quack)
    @fly_behaviour = FlyBehaviour.new(self, fly_behaviour)
    @quack_behaviour = QuackBehaviour.new(self, quack_behaviour)
    @name = name
    end

    def fly
    @fly_behaviour.perform
    end

    def quack
    @quack_behaviour.perform
    end
    end

    class Behaviour
    def initialize(object, behaviour);
    @obj = object;
    @behaviour = behaviour;
    end

    def perform
    send(@behaviour)
    end

    def self.list;
    self.protected_instance_methods
    end
    end

    class FlyBehaviour < Behaviour
    protected
    def fly_with_wings
    puts "#{@obj.name} is flying!"
    end

    def do_not_fly
    puts "#{@obj.name} can't fly. :-("
    end
    end

    class QuackBehaviour < Behaviour
    protected
    def quack
    puts "#{@obj.name} is quacking! Quack!!"
    end

    def squeak
    puts "#{@obj.name} is quacking! Squeak!!!"
    end
    end

    class RubberDuck < Duck
    def initialize(name)
    super(name,:do_not_fly,:squeak)
    end
    end

    ducks = []
    ducks << Duck.new("George")
    ducks << RubberDuck.new("Wacky")

    ducks.each do |duck|
    duck.quack
    duck.fly
    end

    p QuackBehaviour.list
    #================================================

    The next big thing would be to implement generating behaviour-related
    methods in the Duck class on the fly. Through method_missing, maybe?
    And, of course, behaviour instance variables too. That seems a bit
    harder to do, but I'm a programming newbie after all! :) The perfect
    use of the solution would look like:

    usually_able_to :fly, :quack, :swim

    that looks similiar to Rails has_many and belongs_too. Maybe I need to
    check it's code for an idea.

    And there's another question: how to make all methods defined in
    Behaviour children protected? The code would be more attractive if I
    hadn't to write "protected" in the beginning of each behaviour child.
     
    Vladimir Agafonkin, Jan 24, 2006
    #7
    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. Alvin Bruney

    Threads.. Session var lost, App var ok

    Alvin Bruney, Dec 2, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    381
    rooster575
    Dec 2, 2003
  2. thomson
    Replies:
    10
    Views:
    2,527
    Eliyahu Goldin
    Jun 20, 2005
  3. thomson
    Replies:
    0
    Views:
    404
    thomson
    Jun 20, 2005
  4. Neville Dempsey
    Replies:
    1
    Views:
    274
    Bruno Desthuilliers
    Sep 1, 2008
  5. Sven-Thorsten Fahrbach
    Replies:
    3
    Views:
    114
    Sven-Thorsten Fahrbach
    Jul 30, 2005
Loading...

Share This Page