Difficult Inheritance Problem

This is a discussion on Difficult Inheritance Problem within the RUBY forums in Programming Languages category; Hi all, I have a problem I can't think of a solution to with regard to inheritence. I have an abstract class that others inherit from: class DataObject class << self attr_accessor :difference_mapping ... end ... end The descendents of this class each define their own difference mapping: class Page < DataObject self.difference_mapping = {:blah => :blah} end I would now like to inherit from the Page class but use its difference_mapping. Obviously this does not work because the attr_accessor in the DataObject uses a class instance variable that is unique to each class. I tried using a proper class ...

Go Back   Application Development Forum > Programming Languages > RUBY

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #1  
Old 08-27-2008, 05:08 AM
Toby Clemson
Guest
 
Default Difficult Inheritance Problem

Hi all,

I have a problem I can't think of a solution to with regard to
inheritence.
I have an abstract class that others inherit from:

class DataObject
class << self
attr_accessor :difference_mapping

...
end
...
end

The descendents of this class each define their own difference
mapping:

class Page < DataObject
self.difference_mapping = {:blah => :blah}
end

I would now like to inherit from the Page class but use its
difference_mapping. Obviously this does not work because the
attr_accessor in the DataObject uses a class instance variable that is
unique to each class. I tried using a proper class variable
(@@difference_mapping) but that is the same for all descending
classes.

Is there a way to define a class level variable that descends down the
inheritance tree unless it is overridden in the same way as this is
possible for methods? I mean I could wrap the data structure in a
method but that does not seem like a very clean solution.

Thanks in advance,
Toby

Reply With Quote
  #2  
Old 08-27-2008, 05:46 AM
Martin Boese
Guest
 
Default Re: Difficult Inheritance Problem

Hi,

I am using something like below for my program. I trick is to use methods
instead of class variables as they persist through inheritance.

Martin


class A
def self.define_attr_method(name, value=nil)
sing = class << self; self; end
sing.class_eval "def #{name}; #{value.inspect}; end"
end

# Sets and/or returns current difference_mapping
def self.difference_mapping(value = nil)
self.define_attr_method('difmap', value) unless value.nil?
self.difmap
end
end

class B < A
difference_mapping 'class B'
end

class C < B
end

class D < B
difference_mapping 'class D'
end

puts B.difference_mapping
puts C.difference_mapping
puts D.difference_mapping


This will print:
class B
class B
class D



On Wednesday 27 August 2008 09:08:43 Toby Clemson wrote:
> Hi all,
>
> I have a problem I can't think of a solution to with regard to
> inheritence.
> I have an abstract class that others inherit from:
>
> class DataObject
> class << self
> attr_accessor :difference_mapping
>
> ...
> end
> ...
> end
>
> The descendents of this class each define their own difference
> mapping:
>
> class Page < DataObject
> self.difference_mapping = {:blah => :blah}
> end
>
> I would now like to inherit from the Page class but use its
> difference_mapping. Obviously this does not work because the
> attr_accessor in the DataObject uses a class instance variable that is
> unique to each class. I tried using a proper class variable
> (@@difference_mapping) but that is the same for all descending
> classes.
>
> Is there a way to define a class level variable that descends down the
> inheritance tree unless it is overridden in the same way as this is
> possible for methods? I mean I could wrap the data structure in a
> method but that does not seem like a very clean solution.
>
> Thanks in advance,
> Toby




Reply With Quote
  #3  
Old 08-27-2008, 05:54 AM
James Coglan
Guest
 
Default Re: Difficult Inheritance Problem

[Note: parts of this message were removed to make it a legal post.]

> Is there a way to define a class level variable that descends down the
> inheritance tree unless it is overridden in the same way as this is
> possible for methods? I mean I could wrap the data structure in a
> method but that does not seem like a very clean solution.




Try this, perhaps:



class DataObject
class << self
attr_writer :mapping

def mapping
@mapping || (self == DataObject ? nil : superclass.mapping)
end
end
end

class Page < DataObject; end

DataObject.mapping = 'foo'

puts Page.mapping #=> 'foo'



You could write a class helper to generate these methods. I think Rails has
something called 'write_inheritable_attribute' somewhere that does the same
thing.

Reply With Quote
  #4  
Old 08-27-2008, 06:08 AM
Frederick Cheung
Guest
 
Default Re: Difficult Inheritance Problem


On 27 Aug 2008, at 10:08, Toby Clemson wrote:
>
> I would now like to inherit from the Page class but use its
> difference_mapping. Obviously this does not work because the
> attr_accessor in the DataObject uses a class instance variable that is
> unique to each class. I tried using a proper class variable
> (@@difference_mapping) but that is the same for all descending
> classes.
>
> Is there a way to define a class level variable that descends down the
> inheritance tree unless it is overridden in the same way as this is
> possible for methods? I mean I could wrap the data structure in a
> method but that does not seem like a very clean solution.
>


two possible approaches are rails' class_inheritable_accessor and
superclass_delegating_accessor.

Both lean on class instance variables. In the case of
class_inheritable_accessor the attributes are store in a hash and
self.inherited is hooked to copy that hash over when a subclass is
created

superclass_delegating_accessor looks for an appropriate instance
variable and if it does not exist calls the superclass (stopping when
it gets to the the class that created the
superclass_delegating_accessor). Writing however always writes to an
instance variable of the class being changed. I put some more detail
about them at http://www.spacevatican.org/2008/8/1...lass-variables

Fred
> Thanks in advance,
> Toby
>



Reply With Quote
  #5  
Old 08-27-2008, 06:28 AM
Robert Dober
Guest
 
Default Re: Difficult Inheritance Problem

On Wed, Aug 27, 2008 at 11:08 AM, Toby Clemson <tobyclemson@gmail.com> wrote:
I am currently working on a new release of Labardor, but there still
is sooo much to do, however, you might be interested in the following
code of Labrador.
I am however aware that this implies a rethink of your strategy,
however one of my goals is to explore different behavior based OO
approaches than inheritance and mixins, in case you find that a useful
paradigm shift.
And I appologize for the long post but Labrador just is in no shape
for a new release to Rubyforge.

HTH
Robert
Skip the rest if you are not particularily interested in different OO
approaches.
----------------------------- 8< ------------------------
#--
# vim: sts=2 sw=2 tw=0 expandtab nu:
#*
#* Labrador, The Lazy Programmer's Best Friend.
#*
#* Distributed under the terms of the BSD License.
#* Copyright (c) 2007 Robert Dober
#* All rights reserved.
#*
#* Redistribution and use in source and binary forms, with or without
#* modification, are permitted provided that the following conditions are met:
#* * Redistributions of source code must retain the above copyright
#* notice, this list of conditions and the following disclaimer.
#* * Redistributions in binary form must reproduce the above copyright
#* notice, this list of conditions and the following disclaimer in the
#* documentation and/or other materials provided with the distribution.
#* * Neither the name of the Labrador packahe nor the
#* names of its contributors may be used to endorse or promote products
#* derived from this software without specific prior written permission.
#*
#* THIS SOFTWARE IS PROVIDED BY Robert Dober ``AS IS'' AND ANY
#* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#* DISCLAIMED. IN NO EVENT SHALL Robert Dober BE LIABLE FOR ANY
#* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#++

class Array

def ivar_names_to_strings
map { |ele| ele.to_s.sub("@","") }
end

def ivar_names_to_symbols
map { |ele| ele.to_s.sub("@","").to_sym }
end
def names_to_ivar_strings
map { |ele| "@#{ele.to_s.sub("@","")}" }
end

def names_to_ivar_symbols
map { |ele| "@#{ele.to_s.sub("@","")}".to_sym }
end

end # class Array


class Object
def get_ivars *ivars
ivars = instance_variables if ivars.empty?
ivars.ivar_names_to_symbols.
inject( {} ) { |h, ivar|
h.update ivar => instance_variable_get( "@#{ivar}" )
}
end

def pop_ivars
set_ivars! @__ivar_stack__.pop
end

def push_ivars hash
( @__ivar_stack__ ||= [] ).
push(
get_ivars( *hash.keys )
)
set_ivars! hash
end

def set_ivars hash
hash.keys.each do
| ivar |
ivar_name = "@#{ivar}".sub( /^@@/, "@" )
instance_variable_set ivar_name, hash[ ivar ] unless
instance_variables.include? ivar_name
end
end

def set_ivars! hash
hash.keys.each do
| ivar |
ivar_name = "@#{ivar}".sub( /^@@/, "@" )
instance_variable_set ivar_name, hash[ ivar ]
end
end

def set_only_ivars hash, *keys
set_ivars hash.keys.inject( {} ){ |h, k|
keys.include?( k ) ? h.update( k => hash[k] ) : h
}
end # def set_only_ivars hash, *keys

def set_only_ivars! hash, *keys
set_ivars! hash.keys.inject( {} ){ |h, k|
keys.include?( k ) ? h.update( k => hash[k] ) : h
}
end # def set_only_ivars hash, *keys
end # class Object

class Behavior
attr_reader :block
def initialize &blk
@block = blk
end
end

module Kernel
def Behavior &blk
Behavior::new &blk
end
end

class Module
def empty?; instance_methods.empty? end
def empty!; instance_methods.each do |im| remove_method im end end
end

module Pushable
CannotPopException = Class::new RuntimeError
ArgumentError = Class::new ::ArgumentError

def pop_behavior
@__bsp__ -= 1
raise CannotPopException, "empty entity #{self}" if @__bsp__ < 0
@__behavior_stack__[@__bsp__].empty!
end

def push_behavior *behaviors, &blk
@__behavior_stack__ ||= []
@__bsp__ ||= 0
raise ArgumentError,
"push_behavior takes at least one behavior or block" if
behaviors.empty? and blk.nil?

behaviors.each do |behavior|
_push_behavior behavior
end

_push_behavior blk if blk
self
end

private

def _push_behavior behavior
m = @__behavior_stack__[@__bsp__]
@__behavior_stack__ << ( m = Module::new ) unless m
include m rescue extend m # this is autoprotected against double
inclusion; so finally turns out it is a feature
m.empty!
m.module_eval &(behavior.block rescue behavior)
@__bsp__ += 1
end
end # module Pushable

class << Pushable
def new *args, &blk
c = Class::new( *args, &blk )
c.extend self
c
end
end # class << Pushable

class << PushableModule = Module::new
def new *args, &blk
m = Module::new( *args, &blk )
m.extend Pushable
m
end
end
------------------------------------ 8<
-----------------------------------------

Reply With Quote
  #6  
Old 08-27-2008, 07:37 AM
David A. Black
Guest
 
Default Re: Difficult Inheritance Problem

Hi --

On Wed, 27 Aug 2008, Toby Clemson wrote:

> Hi all,
>
> I have a problem I can't think of a solution to with regard to
> inheritence.
> I have an abstract class that others inherit from:
>
> class DataObject
> class << self
> attr_accessor :difference_mapping
>
> ...
> end
> ...
> end
>
> The descendents of this class each define their own difference
> mapping:
>
> class Page < DataObject
> self.difference_mapping = {:blah => :blah}
> end
>
> I would now like to inherit from the Page class but use its
> difference_mapping. Obviously this does not work because the
> attr_accessor in the DataObject uses a class instance variable that is
> unique to each class. I tried using a proper class variable
> (@@difference_mapping) but that is the same for all descending
> classes.
>
> Is there a way to define a class level variable that descends down the
> inheritance tree unless it is overridden in the same way as this is
> possible for methods? I mean I could wrap the data structure in a
> method but that does not seem like a very clean solution.


The easiest way I can think of is:

class Page
class << self
attr_accessor :difference_mapping
end
def self.inherited(c)
c.difference_mapping = difference_mapping
end
end

Page.difference_mapping = { :blah => :blah }

class Next < Page
end

p Next.difference_mapping # { :blah => :blah }


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL
See http://www.rubypal.com for details and updates!

Reply With Quote
  #7  
Old 08-27-2008, 07:44 AM
James Coglan
Guest
 
Default Re: Difficult Inheritance Problem

[Note: parts of this message were removed to make it a legal post.]

>
> The easiest way I can think of is:
>
> class Page
> class << self
> attr_accessor :difference_mapping
> end
> def self.inherited(c)
> c.difference_mapping = difference_mapping
> end
> end
>
> Page.difference_mapping = { :blah => :blah }
>
> class Next < Page
> end
>
> p Next.difference_mapping # { :blah => :blah }




Depends whether you only need the definition done once. This technique will
not cause the subclass to reflect the parent class' value if it is changed,
e.g.:

Page.difference_mapping = {:foo => :something}
Next.difference_mapping #=> {:blah => :blah}

Reply With Quote
  #8  
Old 08-27-2008, 07:51 AM
David A. Black
Guest
 
Default Re: Difficult Inheritance Problem

Hi --

On Wed, 27 Aug 2008, James Coglan wrote:

>>
>> The easiest way I can think of is:
>>
>> class Page
>> class << self
>> attr_accessor :difference_mapping
>> end
>> def self.inherited(c)
>> c.difference_mapping = difference_mapping
>> end
>> end
>>
>> Page.difference_mapping = { :blah => :blah }
>>
>> class Next < Page
>> end
>>
>> p Next.difference_mapping # { :blah => :blah }

>
>
>
> Depends whether you only need the definition done once. This technique will
> not cause the subclass to reflect the parent class' value if it is changed,
> e.g.:
>
> Page.difference_mapping = {:foo => :something}
> Next.difference_mapping #=> {:blah => :blah}


True, but the OP described it as: "Is there a way to define a class
level variable that descends down the inheritance tree unless it is
overridden in the same way as this is possible for methods?" In the
method case, you'd have:

class A
def x; 1; end
end

class B < A
end

class C < A
def x; 2; end
end

and even if A changed x, C would still have its override in effect. So
the same deal with the attribute might be OK in this case.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL
See http://www.rubypal.com for details and updates!

Reply With Quote
  #9  
Old 08-27-2008, 08:51 AM
Robert Dober
Guest
 
Default Re: Difficult Inheritance Problem

On Wed, Aug 27, 2008 at 1:37 PM, David A. Black <dblack@rubypal.com> wrote:
Wow that is great, I would call them viral class variables!
R.

Reply With Quote
  #10  
Old 08-27-2008, 08:55 AM
David A. Black
Guest
 
Default Re: Difficult Inheritance Problem

Hi --

On Wed, 27 Aug 2008, Robert Dober wrote:

> On Wed, Aug 27, 2008 at 1:37 PM, David A. Black <dblack@rubypal.com> wrote:
> Wow that is great, I would call them viral class variables!


I think class variables are already viral :-)


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL
See http://www.rubypal.com for details and updates!

Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 08:41 PM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.