Inner Class Relationship

I have an inner class that needs to send it's parent object (outer class) a message when a certain event occurs.

I would rather not create a method in the outer class for this as it is a messy implementation detail that should be hidden away under lock and key.

Any suggestions for a clean way to implement this? It's a blind spot for me.

Thanks.

James Edward Gray II

If I understand correctly, try passing self of parent to the the inner object
when it's created.

  class Inner
    def initialize( parent )
      @parent = parent
    end
  end

  class Outer
    def initialize
      Inner.new(self)
    end
  end

With any luck, in the future we will have a "caller" method that can refer to
the parent object from Inner#initialize, i.e. without having to specifically
pass self. (Personally I've always thought #object_parent should be built-in
anyway.)

T.

···

On Saturday 20 November 2004 05:31 pm, James Edward Gray II wrote:

I have an inner class that needs to send it's parent object (outer
class) a message when a certain event occurs.

I would rather not create a method in the outer class for this as it is
a messy implementation detail that should be hidden away under lock and
key.

Any suggestions for a clean way to implement this? It's a blind spot
for me.

Thanks.

James Edward Gray II

Since you haven't said much about how you're using this, maybe my answer will be a little presumptive, but: Is there are a particular reason you want the inner class to relate to the outer class this way? When I used inner classes (which is a lot), the relationship between the two is usually fairly clear: The outer class uses an instance of the inner class to delegate some small piece of logic, but the inner class doesn't know much about the outer class as a whole and doesn't change its state.

Something like:

class Outer
  def outer_method
    inner = Inner.new
    result = inner.inner_method
    do_something_based_on result
  end

  class Inner
    def inner_method
    end
  end
end

It's possible that doing it this way violates Tell Don't Ask, but it seems to work fine for me.

F.

···

On Nov 20, 2004, at 5:31 PM, James Edward Gray II wrote:

I have an inner class that needs to send it's parent object (outer class) a message when a certain event occurs.

I would rather not create a method in the outer class for this as it is a messy implementation detail that should be hidden away under lock and key.

Any suggestions for a clean way to implement this? It's a blind spot for me.

Thanks.

James Edward Gray II

Francis Hwang

I don't know what it is about me and not being able to properly convey what I mean the first time. :smiley:

What you posted, is more or less what I'm doing. My desire was to find a way around using a PUBLIC method in the outer class. It's really a message that only the inner class should be able to send.

James Edward Gray II

···

On Nov 20, 2004, at 5:01 PM, trans. (T. Onoma) wrote:

If I understand correctly, try passing self of parent to the the inner object
when it's created.

  class Inner
    def initialize( parent )
      @parent = parent
    end
  end

  class Outer
    def initialize
      Inner.new(self)
    end
  end

With any luck, in the future we will have a "caller" method that can refer to
the parent object from Inner#initialize, i.e. without having to specifically
pass self. (Personally I've always thought #object_parent should be built-in
anyway.)

Yes.

Even if I separate the two classes, my questions remain unchanged: What's a good way to allow one type of object to send private-ish messages to another type of object?

As for details: My outer class is a server. My inner class is a connection for that server. When a connection ends, I need a way to notify the Server object to remove it from it's maintenance list. That's the message I'm wanting to hide from the outside world.

Thanks for the suggestions.

James Edward Gray II

···

On Nov 20, 2004, at 5:55 PM, Francis Hwang wrote:

Since you haven't said much about how you're using this, maybe my answer will be a little presumptive, but: Is there are a particular reason you want the inner class to relate to the outer class this way?

Making a guess, you're four objects down a hierarchy chain and want to reach
up a few levels? That been my experience, but have never found a better
solution. You still have to have some _reference_ to that outer object
--that's the problem. You might try something like this if you can determine
reasonable keys.

class Outer
   def initialize
     @@gimme[:akey] = self
   end
   def self.gimme(key)
     @@gimme[key]
   end
end

Also you could do what what you're doing now but inversely. Something like:

  class Outer
    o = Inner.new
    (class << o; self; end).send(:define_method, :parent){ self }
  end

T.

···

On Saturday 20 November 2004 06:10 pm, James Edward Gray II wrote:

On Nov 20, 2004, at 5:01 PM, trans. (T. Onoma) wrote:
> If I understand correctly, try passing self of parent to the the inner
> object
> when it's created.
>
> class Inner
> def initialize( parent )
> @parent = parent
> end
> end
>
> class Outer
> def initialize
> Inner.new(self)
> end
> end
>
> With any luck, in the future we will have a "caller" method that can
> refer to
> the parent object from Inner#initialize, i.e. without having to
> specifically
> pass self. (Personally I've always thought #object_parent should be
> built-in
> anyway.)

I don't know what it is about me and not being able to properly convey
what I mean the first time. :smiley:

What you posted, is more or less what I'm doing. My desire was to find
a way around using a PUBLIC method in the outer class. It's really a
message that only the inner class should be able to send.

[James Edward Gray II <james@grayproductions.net>, 2004-11-21 01.22 CET]

Even if I separate the two classes, my questions remain unchanged:
What's a good way to allow one type of object to send private-ish
messages to another type of object?

As for details: My outer class is a server. My inner class is a
connection for that server. When a connection ends, I need a way to
notify the Server object to remove it from it's maintenance list.
That's the message I'm wanting to hide from the outside world.

This is a little contrived, and maybe the best option is to just use a
public method.

class Outer
  def remove x
    puts "removing #{x}"
  end
  private :remove
  
  def initialize
    @exportable_private_methods = {
      "remove" => lambda {|x| remove x}
    }
  end
  
  class Inner
    def initialize outer_methods
      @outer_methods = outer_methods
    end
    
    def run
      puts "running"
      @outer_methods["remove"].call(self)
    end
  end
  
  def run
    Inner.new(@exportable_private_methods).run
  end
end

Outer.new.run

# =>
running
removing #<Outer::Inner:0x402bc2c8>

Maybe part of the question has to do with the nature of private-ness in Ruby .... I don't think it's easy in Ruby to have a sort of C++-like friend relationship, where you privilege certain classes to call certain methods. (I did something like this in my ContextualService classes for Lafcadio, by checking caller, but it's sort of a kludge and I wouldn't necessarily recommend it for general use.)

But then, what do we mean by private? What if you just hid the method in the RDoc? Do you imagine a situation where people might use it incorrectly, either by accident or maliciously? This differs depending on how the code's going to be used, of course.

Also, have you considered using Observable?

Francis Hwang

···

On Nov 20, 2004, at 7:22 PM, James Edward Gray II wrote:

On Nov 20, 2004, at 5:55 PM, Francis Hwang wrote:

Since you haven't said much about how you're using this, maybe my answer will be a little presumptive, but: Is there are a particular reason you want the inner class to relate to the outer class this way?

Yes.

Even if I separate the two classes, my questions remain unchanged: What's a good way to allow one type of object to send private-ish messages to another type of object?

As for details: My outer class is a server. My inner class is a connection for that server. When a connection ends, I need a way to notify the Server object to remove it from it's maintenance list. That's the message I'm wanting to hide from the outside world.

class Inner
  attr_accessor :callback

  def initialize
    @callback = do
      #nothing
    end
  end

  def somethingHappens
    @callback.call
  end
end

class Outer
  def initialize
    @inner = Inner.new
    @inner.callback = do
      # something that is totally internal
    end
  end
end

···

On Sun, 21 Nov 2004 08:10:30 +0900, James Edward Gray II wrote:

What you posted, is more or less what I'm doing. My desire was to find
a way around using a PUBLIC method in the outer class. It's really a
message that only the inner class should be able to send.

--
Neil Stevens - neil@hakubi.us
"The world is a dangerous place to live; not because of the people who
are evil, but because of the people who don't do anything about it."
                                                 -- Albert Einstein(?)

James Edward Gray II wrote:

Since you haven't said much about how you're using this, maybe my answer will be a little presumptive, but: Is there are a particular reason you want the inner class to relate to the outer class this way?

Yes.

Even if I separate the two classes, my questions remain unchanged: What's a good way to allow one type of object to send private-ish messages to another type of object?

As for details: My outer class is a server. My inner class is a connection for that server. When a connection ends, I need a way to notify the Server object to remove it from it's maintenance list. That's the message I'm wanting to hide from the outside world.

Thanks for the suggestions.

James Edward Gray II

James,

What you need is FreeBase. FreeBAse is a databus written by Rich Kilmer that we extensively use in the FreeRIDE project (Ruby IDE). It allows any Ruby object to publish nodes in a tree -like hierarchy and other Ruby object to listen to what's happening to these nodes.

It's a sort of a meeting point for Roby object doesn't know or doesn't want to know about each other. You can get Freebase from the FreeRIDE source code. It's a self contain piece of code that we haven't touched for moths so it is farly stable.

The source file is at: http://rubyforge.org/frs/download.php/1641/freeride-0.8.0.tar.gz
extract it and take the freebase directory from there.

I have cc'ed Rich Kilmer as I know he was thinking of packaging Freebase separately but I could not find it.

Laurent

···

On Nov 20, 2004, at 5:55 PM, Francis Hwang wrote:

My desire was to find
a way around using a PUBLIC method in the outer class. It's really a
message that only the inner class should be able to send.

How about,

outer.send(:private_method_in_outer, foo, bar)

or

outer.instance_eval { private_method_in_outer(foo, bar) }

?

Technically anybody can call private methods that way, but
they have to go out of their way to do so.

Regards,

Bill

···

From: "James Edward Gray II" <james@grayproductions.net>

I know this is a retarded problem, but somehow I managed to set things up
such that I get an error when running "Rails Todo". Rather than creating the
directory structure (etc) I just get an error:

C:/cs/ruby/bin/rails:9:in 'system': Exec format error - rake fresh_rpa_rails
(Errno::ENOEXEC)
          from C:/cs/ruby/bin/rails:9

Does anyone recognize the above and know what I need to do about it? I
appreciate your help very much!

Regards, Abe

Also, you may be interested in this:

  http://raa.ruby-lang.org/list.rhtml?name=access

···

On Saturday 20 November 2004 08:35 pm, Francis Hwang wrote:

But then, what do we mean by private? What if you just hid the method
in the RDoc? Do you imagine a situation where people might use it
incorrectly, either by accident or maliciously? This differs depending
on how the code's going to be used, of course.

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

[8,16,20,29,78,65,2,14,26,12,12,28,71,114,12,13,12,82,72,21,17,4,10,2,95].
each_with_index{|x,i| $><<(x^'Begin landing your troops'[i]).chr}
-Tadayoshi Funaba

How about something like this:

class Outer
   class Inner
     def initialize(&block)
       @cleaner = block
     end

     def close
       @cleaner.call self
     end
   end

   def create_inner
     inner = Inner.new { |_inner|
       remove_inner(_inner)
     }
     ...
   end

   private

···

On Nov 20, 2004, at 5:20 PM, Carlos wrote:

[James Edward Gray II <james@grayproductions.net>, 2004-11-21 01.22 CET]

Even if I separate the two classes, my questions remain unchanged:
What's a good way to allow one type of object to send private-ish
messages to another type of object?

As for details: My outer class is a server. My inner class is a
connection for that server. When a connection ends, I need a way to
notify the Server object to remove it from it's maintenance list.
That's the message I'm wanting to hide from the outside world.

   #######
   def remove_inner
     ...
   end
end

Sincerely,
Gennady Bystritsky

Francis Hwang wrote:

[snip]

Also, have you considered using Observable?

I have to go with Francis's suggestion on this. Using Observable to implement the Observer pattern sounds almost like a hand/glove fitting for your problem.

Zach

I missed a couple 'Proc.new's in there, but the idea should be clear
enough I hope.

···

On Sun, 21 Nov 2004 03:41:47 +0000, Neil Stevens wrote:

class Inner
  attr_accessor :callback

  def initialize
    @callback = do
      #nothing
    end
  end

  def somethingHappens
    @callback.call
  end
end

class Outer
  def initialize
    @inner = Inner.new
    @inner.callback = do
      # something that is totally internal
    end
  end
end

--
Neil Stevens - neil@hakubi.us
"The world is a dangerous place to live; not because of the people who
are evil, but because of the people who don't do anything about it."
                                                 -- Albert Einstein(?)

This is a good point. I learned my OO in Java, so I'm naturally paranoid. What you suggest here is probably the most "Ruby" solution and would serve fine. Violate the documentation and all bets are off anyway, right?

I am trying to be more open. I'm warming to Duck Typing, slowly but surely. Please be patient with us paranoid people and kindly refocus us when we're going overboard.

Thanks.

James Edward Gray II

···

On Nov 20, 2004, at 7:35 PM, Francis Hwang wrote:

But then, what do we mean by private? What if you just hid the method in the RDoc?

Abraham Vionas wrote:

I know this is a retarded problem, but somehow I managed to set things up
such that I get an error when running "Rails Todo". Rather than creating the
directory structure (etc) I just get an error:

Can you post the actual command you are running?

James

It has the exact same flaw actually, update() must be public.

My thanks to all though. You did give me what I need (multiple options!) and I'm grateful.

James Edward Gray II

···

On Nov 20, 2004, at 9:33 PM, Zach Dennis wrote:

Francis Hwang wrote:

[snip]
Also, have you considered using Observable?

I have to go with Francis's suggestion on this. Using Observable to implement the Observer pattern sounds almost like a hand/glove fitting for your problem.

Could you try to edit C:/cs/ruby/bin/rails and change line 9 to
    system %{rake.bat fresh_rpa_rails}
?

···

On Sun, Nov 21, 2004 at 11:19:35AM +0900, Abraham Vionas wrote:

I know this is a retarded problem, but somehow I managed to set things up
such that I get an error when running "Rails Todo". Rather than creating the
directory structure (etc) I just get an error:

C:/cs/ruby/bin/rails:9:in 'system': Exec format error - rake fresh_rpa_rails
(Errno::ENOEXEC)
          from C:/cs/ruby/bin/rails:9

Does anyone recognize the above and know what I need to do about it? I
appreciate your help very much!

--
Hassle-free packages for Ruby?
RPA is available from http://www.rubyarchive.org/