Forum: Ruby Inherit and override in the same time?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Philippe L. (Guest)
on 2009-02-16 17:30
(Received via mailing list)
Hi Ruby gurus,

Let's say we have a Parent class, and a Child1 class that inherits from
the Parent class.

I'd like to create a Child2 class that inherits most of the Child1
class, except for one method, which I'd like to override completely. The
problem is that I need to call the method in the Parent class, and
apparently "super.super" is not supported:

----------------------------
class Parent
 def go
   puts 'parent'
 end
end

class Child1 < Parent
 def go
   super
   puts 'child1'
 end
 def a_method_id_like_to_inherit
 end
end

class Child2 < Child1
 def go
   super.super
   puts 'child2'
 end
end

Child2.new.go
----------------------------
in `go': undefined method `super' for nil:NilClass (NoMethodError)
----------------------------

I ended up doing this, which apprently works.

----------------------------
class Parent
 def go
   puts 'parent'
 end
end

class Child1 < Parent
 def go
   super
   puts 'child1'
 end
 def a_method_id_like_to_inherit
 end
end

class Child2 < Child1
 def go
   self.class.superclass.superclass.instance_method( :go ).bind( self
).call
   puts 'child2'
 end
end

Child2.new.go
----------------------------
parent
child2
----------------------------

Isn't there anything simpler than that? Or is that kind of pattern
considered as bad design maybe?

Philippe
James C. (Guest)
on 2009-02-16 17:46
(Received via mailing list)
> class Child1 < Parent
>   self.class.superclass.superclass.instance_method( :go ).bind( self
>
> Isn't there anything simpler than that? Or is that kind of pattern
> considered as bad design maybe?


Smells a little of bad design. Consider putting the common methods for
Child1, Child2 into a module:

class Parent
end

class Child1 < Parent
  include ChildStuff
end

class Child2 < Parent
  include ChildStuff
end

Just a suggestion -- it's hard to really comment on a design without
knowing
the problem you're trying to solve.
Rick D. (Guest)
on 2009-02-16 17:48
(Received via mailing list)
On Mon, Feb 16, 2009 at 10:29 AM, Philippe L.
<removed_email_address@domain.invalid> wrote:

> ----------------------------
>  end
>
>   puts 'parent'
> end
> ----------------------------
> parent
> child2
> ----------------------------
>
> Isn't there anything simpler than that? Or is that kind of pattern
> considered as bad design maybe?
>
>
It's not clear WHY you want to do this but..

your
self.class.superclass.superclass.instance_method(:go).bind(self).call

really doesn't do the same thing, in general as your desired super.super
(which I've not by the way seen in other dynamic OO languages either).

Consider what would happen if you added

class Child3 < Child2
end

Child3.new.go

I think that the right way to do this is to refactor the method to
extract
just the behavior you want to control, so in this particular case
something
like

class Parent
 def go
  puts 'parent'
 end
end

class Child1 < Parent

 def put_me
   puts 'child1'
 end

 def go
  super
  put_me
 end

end

class Child2 < Child1
 def put_me
  puts 'child2'
 end
end

class Child3 < Child2
end

Parent.new.go
Child1.new.go
Child2.new.go
Child3.new.go

HTH

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
Philippe L. (Guest)
on 2009-02-16 18:26
(Received via mailing list)
Rick DeNatale wrote:

>> Hi Ruby gurus,
>>
>> Let's say we have a Parent class, and a Child1 class that inherits
>> from the Parent class.
>>
>> I'd like to create a Child2 class that inherits most of the Child1
>> class, except for one method, which I'd like to override completely.
>> The problem is that I need to call the method in the Parent class,
>> and apparently "super.super" is not supported:

> It's not clear WHY you want to do this but..

Hi Rick and James,

Thanks for your answer.

I tried to rewrite my example so it shows a little bit better WHY I'm
trying to do that.

------------------------------------

class Form
 def initialize
   puts "form preparation"
 end
 def search_data
   puts "form search preparation"
   yield
   puts "form search cleanup"
 end
end

class ProductForm < Form
 def initialize
   super
   puts "product form widgets preparation"
 end
 def search_data
   super do
    puts "product search"
   end
  end
end

class ArchivedProductForm < ProductForm
 def search_data
   self.class.superclass.superclass.instance_method( :search_data
).bind( self ).call do
     puts "archived product search"
   end
  end
end

ProductForm.new.search_data
puts "------------------"
ArchivedProductForm.new.search_data

------------------------------------
form preparation
product form widgets preparation
form search preparation
product search
form search cleanup
------------------
form preparation
product form widgets preparation
form search preparation
archived product search
form search cleanup
------------------------------------

Basically, a ProductForm or ArchivedProductForm are identical, except
the way they are being searched for. All the rest, like the widgets on
the form, are exactly the same.

I'm pretty sure now I have to refactor somehow my code, to keep things
clean. I guess the following code, with an extra class, is the way to
go:

------------------------------------

class Form
 def initialize
   puts "form preparation"
 end
 def search_data
   puts "form search preparation"
   yield
   puts "form search cleanup"
 end
end

class ProductBaseForm < Form
 def initialize
   super
   puts "product form widgets preparation"
 end
end

class ProductForm < ProductBaseForm
 def search_data
   super do
     puts "product search"
   end
  end
end

class ArchivedProductForm < ProductBaseForm
 def search_data
   super do
     puts "archived product search"
   end
  end
end

ProductForm.new.search_data
puts "------------------"
ArchivedProductForm.new.search_data

------------------------------------
form preparation
product form widgets preparation
form search preparation
product search
form search cleanup
------------------
form preparation
product form widgets preparation
form search preparation
archived product search
form search cleanup
------------------------------------

Best regards,

Philippe
Pit C. (Guest)
on 2009-02-16 20:31
(Received via mailing list)
2009/2/16 Philippe L. <removed_email_address@domain.invalid>:
> I tried to rewrite my example so it shows a little bit better WHY I'm
> trying to do that.

Philippe, you could introduce a new method, for example #product_search:

class Form
  def initialize
    puts "form preparation"
  end
  def search_data
    puts "form search preparation"
    yield
    puts "form search cleanup"
  end
end

class ProductForm < Form
  def initialize
    super
    puts "product form widgets preparation"
  end
  def search_data
    super do
      product_search
    end
  end
  def product_search
    puts "product search"
  end
end

class ArchivedProductForm < ProductForm
  def product_search
    puts "archived product search"
  end
end

(not tested)

Regards,
Pit
Robert K. (Guest)
on 2009-02-16 23:55
(Received via mailing list)
On 16.02.2009 16:29, Philippe L. wrote:
> ----------------------------
>  end
>
>    puts 'parent'
> end
> ----------------------------
> parent
> child2
> ----------------------------
>
> Isn't there anything simpler than that? Or is that kind of pattern
> considered as bad design maybe?

IMHO the "bug" is in your inheritance design.  You probably should
rather do

class Parent
   def go
     puts 'parent'
   end
end

class BaseChild < Parent
  def a_method_id_like_to_inherit
    puts 'Boo!'
  end
end

class Child1 < BaseChild
  def go
    super
    puts 'child1'
  end
end

class Child2 < BaseChild
  def go
    super
    puts 'child2'
  end
end

Now, if there are no other classes that should derive from Parent you
might as well merge BaseChild and Parent.

Kind regards

  robert
Rick D. (Guest)
on 2009-02-17 00:17
(Received via mailing list)
On Mon, Feb 16, 2009 at 1:28 PM, Pit C.
<removed_email_address@domain.invalid>wrote:

>  def search_data
>  end
> class ArchivedProductForm < ProductForm
>  def product_search
>     puts "archived product search"
>  end
> end
>
>
Exactly!

This is what I recommended, recast into the "new" problem.


--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
This topic is locked and can not be replied to.