Class Level inheritable attributes - are we there yet?

Hi,
I’m having trouble understanding why this isn’t available from the Ruby
core?
Does core not provide an alternative / satisfactory implementation of
this?

clia.rb - Class Level Inheritable Attributes

module ClassLevelInheritableAttributes
def self.included(base)
base.extend(ClassMethods)
end

module ClassMethods
def inheritable_attributes(*args)
@inheritable_attributes ||= [:inheritable_attributes]
@inheritable_attributes += args
args.each do |arg|
class_eval %(
class << self; attr_accessor :#{arg} end
)
end
@inheritable_attributes
end

def inherited(subclass)
  @inheritable_attributes.each do |inheritable_attribute|
    instance_var = "@#{inheritable_attribute}"
    subclass.instance_variable_set(instance_var,

instance_variable_get(instance_var))
end
end
end
end

class Polygon
include ClassLevelInheritableAttributes
inheritable_attributes :sides
@sides = 8
end

puts Polygon.sides # => 8

class Octogon < Polygon; end

puts Polygon.sides # => 8
puts Octogon.sides # => 8

Ref:
http://railstips.org/2006/11/18/class-and-instance-variables-in-ruby

Its rather difficult to believe we must in each case define / require
our own custom module. Please note - i’m not complaining here. I just
want to know whether the above example is “the best solution in use”
for 1.8… 1.9…

Best regards,

dreamcat4
[email protected]

Hi –

On Sun, 11 Oct 2009, dreamcat four wrote:

end

puts Polygon.sides # => 8
puts Octogon.sides # => 8

Ref: http://railstips.org/2006/11/18/class-and-instance-variables-in-ruby

Its rather difficult to believe we must in each case define / require
our own custom module. Please note - i’m not complaining here. I just
want to know whether the above example is “the best solution in use”
for 1.8… 1.9…

I would probably write it a little differently, maybe like this:

module ClassLevelInheritableAttributes
def inheritable_attributes(*args)
(class << self; self; end).class_eval do
attr_accessor *args
end

 @inheritable_attributes ||= []
 @inheritable_attributes.concat(args)

end

def inherited(subclass)
@inheritable_attributes.each do |attr|
subclass.send("#{attr}=", send(attr))
end
super
end
end

class Whatever
extend ClassLevelInheritableAttributes
end

etc. I’m not sure it’s a common enough idiom to be worthy of a new
language construct, though. I love the fact that you can make what are
essentially language-level-like constructs from a few lines of code in
Ruby. I think that very, very few of them should be promoted to the
actual language.

David


The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com

David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)

The problem with class variables in Ruby, is that a class variable is
the same object across all subclasses of a class. This is in my
opinion almost never what you’d want. More probable is that you’d want
the individual class instance to have an accessor. (Remember classes
are objects in Ruby).

dreamcat4
[email protected]

Ah,
I seems that ActiveSupport’s class_inheritable_accessor, seems to do
the same. class_inheritable_accessor (or what I showed) uses instance
variables (@foo) at the Class instance level. These variables are not
shared across all subclasses.

require ‘activesupport’

class Base
class_inheritable_accessor :value
self.value = ‘123’
end

class Derived < Base; end
class Derived2 < Base; end

Derived.value #=> ‘123’
Derived.value = ‘abc’
Base.value #=> ‘123’
Derived2.value #=> '123

It becomes a problem when using a mixture of libraries which all
define methods on Class, Kernel or Object. Obviously namespace clashes
can happen, (and indeed they have already).

Best regards,

dreamcat4
[email protected]

Hi –

On Sun, 11 Oct 2009, dreamcat four wrote:

The problem with class variables in Ruby, is that a class variable is
the same object across all subclasses of a class. This is in my
opinion almost never what you’d want. More probable is that you’d want
the individual class instance to have an accessor. (Remember classes
are objects in Ruby).

Oh, there are lots of problems with class variables :slight_smile: I didn’t
mention them. Was there something in my post that made it sound like I
was suggesting class variables?

David


The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com

David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)

On Sat, Oct 10, 2009 at 8:10 PM, David A. Black [email protected]
wrote:

was suggesting class variables?
No, its just a generally accepted problem with the ruby language.

dreamcat4
[email protected]

On 10/10/2009 08:59 PM, dreamcat four wrote:

The problem with class variables in Ruby, is that a class variable is
the same object across all subclasses of a class. This is in my
opinion almost never what you’d want. More probable is that you’d want
the individual class instance to have an accessor. (Remember classes
are objects in Ruby).

Class variables are one of the few features I would elect for completely
throwing out of the language since they are complex, can be error prone
(initialization order matters) and use cases are rare (if existent at
all).

Having said that I am not sure that you actually need a language
construct when you can do this:

class A
class <<self
def foo
@foo || superclass.foo
end
end

@foo = 1
end

class B < A
end

class C < A
@foo = 2
end

[A,B,C].each do |cl|
printf “%-2s %p\n”, cl, cl.foo
end

[email protected]:/tmp$ ruby1.9 cl.rb
A 1
B 1
C 2

And I completely agree to what David said:

I’m not sure it’s a common enough idiom to be worthy of a new
language construct, though. I love the fact that you can make what are
essentially language-level-like constructs from a few lines of code in
Ruby. I think that very, very few of them should be promoted to the
actual language.

Kind regards

robert

On Sun, Oct 11, 2009 at 6:55 PM, Robert K.
[email protected] wrote:

It shouldn’t be mandated to re-invent the wheel in any programming
language, even if its fun style / fun to write. Here is why Robert:
because you would have just put 2 bugs into your code.

  1. It breaks when you want to set foo = nil in a subclass.
  2. Not having an accessor definition will break other code.

puts A.instance_variables.inspect
=> ["@foo"]
puts B.instance_variables.inspect
=> []
puts C.instance_variables.inspect
=> ["@foo"]

Most people would try / expect to fix by putting attr_accessor :foo at
top class A. It simply doesn’t work and the regular accessor is not
inherited. Because in Ruby the Class is instantiated as an instance of
object. You could probably imagine a little imaginary OO professor
tugging at your clothes and saying ‘tut tut, such a shame’ or
something. And you might argue back that the point was that these
aren’t bugs if you understand the limitations etc, etc. Just like
being back at school eh? But i can assure you when any real programmer
in the real world comes along to use your classes and / or modify your
code, these holes are eventually surface as real breakages / bugs.

Heres my own top 3 recommendations:

  • Give up / don’t use any. Avoid if possible.

  • Use the activeresource class inheritable accessor. I guess that’s
    not so much of a stretch if you are already depending upon
    activeresource for other things.

  • Request a real language implementation in ruby core because class is
    an object. It would be entirely a matter for the ruby development team
    to decide whether they would want to implement it, and/or how. I’m
    very surprised no-one has asked for this on 1.9 line, or to change the
    existing @@ behaviour since are changed the block level variable
    scoping and many other things.

dreamcat4
[email protected]

Hi –

On Mon, 12 Oct 2009, dreamcat four wrote:

  end
 end

It shouldn’t be mandated to re-invent the wheel in any programming
language, even if its fun style / fun to write. Here is why Robert:
because you would have just put 2 bugs into your code.

But using the available techniques in a language to put together
something higher level is not “re-inventing the wheel” (unless you do
it repeatedly). The language cannot be expected to incorporate an
abstract construct for every use case.

  1. It breaks when you want to set foo = nil in a subclass.

You can fix this with a defined? test.

  1. Not having an accessor definition will break other code.

puts A.instance_variables.inspect
=> ["@foo"]
puts B.instance_variables.inspect
=> []
puts C.instance_variables.inspect
=> ["@foo"]

That’s not broken; it just means that what Robert is doing isn’t
identical to what, say, attr_accessor does. You could modify Robert’s
code to assign to the instance variable the first time around rather
than just examining it, or something like that.

Most people would try / expect to fix by putting attr_accessor :foo at
top class A. It simply doesn’t work and the regular accessor is not
inherited.

It is inherited; that is, given this:

class A
attr_accessor :x
end

class B < A
end

instances of B will have an x attribute. But, as you say, this isn’t
relevant to the class instance, and if people try to do it in order to
address class-level state, they just haven’t yet learned enough about
the Ruby object model to know that things don’t work that way. So
they’ll learn :slight_smile:

Because in Ruby the Class is instantiated as an instance of
object. You could probably imagine a little imaginary OO professor

(A class is actually an instance of Class.)

tugging at your clothes and saying ‘tut tut, such a shame’ or
something. And you might argue back that the point was that these
aren’t bugs if you understand the limitations etc, etc. Just like
being back at school eh? But i can assure you when any real programmer
in the real world comes along to use your classes and / or modify your
code, these holes are eventually surface as real breakages / bugs.

I don’t know whether Robert regards them as bugs or not, but I think
the main point is that there a whole world of this stuff you can do
trivially in Ruby. Besides, the examples we send back and forth on
ruby-talk aren’t necessarily fully field-tested; that’s not really the
point of the forum :slight_smile:

to decide whether they would want to implement it, and/or how. I’m
very surprised no-one has asked for this on 1.9 line, or to change the
existing @@ behaviour since are changed the block level variable
scoping and many other things.

I’m still not seeing why it’s so important that it be addressed in the
core. Of course I’d be glad to see @@ changed to something more useful
(Robert and I have been among the most vocal critics of class
variables over the years :slight_smile: but I don’t want to see classes
special-cased when it comes to how they maintain their own state.
They’re objects, and objects maintain state with instance variables,
which classes can easily do.

I’ve often said that “because classes are also objects” is the answer
to 75% of all questions about Ruby :slight_smile: That’s actually why I don’t
like extra special cases for classes. Once people understand that
they’re objects, and let go of trying to view them as entirely
special, many things fall into place and the language makes more
sense.

David


The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com

David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)

On Oct 10, 2:02 pm, dreamcat four [email protected] wrote:

Hi,
I’m having trouble understanding why this isn’t available from the Ruby core?
Does core not provide an alternative / satisfactory implementation of this?

One alternative:

http://rubyworks.github.com/inheritor/

2009/10/11 dreamcat four [email protected]:

end
end

It shouldn’t be mandated to re-invent the wheel in any programming
language, even if its fun style / fun to write.

Which wheel did I reinvent?

puts C.instance_variables.inspect
=> ["@foo"]

David has said everything there is to say about this. I modeled the
quick hack based on your original example which obviously needed to
maintain constant values at class level which would have been better
done like this:

11:07:12 desktop$ ruby19 cl.rb
A 1
B 1
C 2
11:07:24 desktop$ cat cl.rb
class A
Foo = 1
end

class B < A
end

class C < A
Foo = 2
end

[A,B,C].each do |cl|
printf “%-2s %p\n”, cl, cl::Foo
end

If any, that would have been the “bug” in my approach. The code was
merely meant to demonstrate what can be done with a few lines of code
and that accessors (in fact all methods) defined for class instances
are inherited to subclasses.

Regards

robert

On Sun, Oct 11, 2009 at 3:34 PM, dreamcat four [email protected]
wrote:
.

  1. Not having an accessor definition will break other code.

puts A.instance_variables.inspect
=> ["@foo"]
puts B.instance_variables.inspect
=> []
puts C.instance_variables.inspect
=> ["@foo"]

attribute accessors don’t cause instance variables to exist until the
setter (or some other method) initializes the instance variable:

class A
attr_accessor :bar
class << self
attr_accessor :foo
end
end

A.instance_variables # => []
a = A.new
a.instance_variables # => []

A.foo = 42
a.bar = 39

A.instance_variables # => ["@foo"]
a.instance_variables # => ["@bar"]


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Dreamcat F. wrote:

David has shown that we should ‘extend’ and not define any accessor
method. So I guess its the better choice (since pointing out about the
@=nil). Im definately coming around to understand better and appreciate
more David’s solution here. Thank you.

I would change the following line:

  • @inheritable_attributes.each do |attr|
  • inheritable_attributes.each do |attr|

Provide the full usage:

class MyObject < Object
extend ClassLevelInheritableAttributes
inheritable_attributes :attr_1, :attr_2, …
end

Using extend only once and the feature itself will also propagate to all
subclasses.

class MySubclass < MyObject
inheritable_attributes :attr_3, :attr_4, …
end

This means that you could mix into Object, just still left with possible
namespace conflict on 1 new method (‘inheritable_attributes’) as we had
discussed earlier. I don’t believe we can do anything about that here.
Only if defined as an official method would everybody know not to use
it.

Best regards,

dreamcat4
[email protected]

Ah,

dreamcat four wrote:

  • Use the activeresource class inheritable accessor. I guess that’s
    not so much of a stretch if you are already depending upon
    activeresource for other things.

  • Request a real language implementation in ruby core because class is
    an object. It would be entirely a matter for the ruby development team
    to decide whether they would want to implement it, and/or how. I’m
    very surprised no-one has asked for this on 1.9 line, or to change the
    existing @@ behaviour since are changed the block level variable
    scoping and many other things.

I seem to have been wrong about recommending these
activesupport/class_inheritable_accessor. They are not fully up to
scratch.

require “activesupport”
class Cartoon
self.class_inheritable_accessor :_
self._ = “deputy dawg”

def initialize(*args, &block)
puts self.class..inspect
puts self.
.inspect
self._ = “the lazy cat”
puts self..inspect
puts self.class.
.inspect
end
end
Cartoon.new

=>
“deputy dawg”
“deputy dawg”
“the lazy cat”
“the lazy cat”

As you can see, modifying the value in the instantiated object also
modifies the value back in the class object.

So back to ‘clia.rb’ like in the first 2 posts. I was maybe going to
suggest that we should make a new accessor method. But digging deeper we
can see activesupport have already defined ‘cattr_accessor’ aswell (this
time for attributes which aren’t inherited and passed on to either
instances or subclasses).

Then i searched for ‘ciattr_accessor’ in case someone had already made
an inheritable version.
http://atomos.rubyforge.org/svn/atomos/lib/extra.rb Does it do the
required job? No (is another duplication of cattr). Potential namespace
conflict? Yes.

David has shown that we should ‘extend’ and not define any accessor
method. So I guess its the better choice (since pointing out about the
@=nil). Im definately coming around to understand better and appreciate
more David’s solution here. Thank you.

Best regards,

dreamcat4
[email protected]

Its rather difficult to believe we must in each case define / require
our own custom module. Please note - i’m not complaining here. I just
want to know whether the above example is “the best solution in use”
for 1.8… 1.9…

you certainly aren’t complaining and i must say that i’m a little
disappointed in the responses you are getting from people.

let me start out by saying that it is a fact that inheritable class
attributes are both useful and re-invented over and over. do a search
on github, rubyforge, raa, google, and this mailing list and you will
find hundreds of examples. github alone has 237 pages of results for
this search in many languages. i’d also point out that there are
really two kinds of rubyists: those who write code for themselves and
those who write code for others. if you systematically do searches
(on the same sources as above) for the people are against permutations
of class state vs. people are for it you will see a trend: people who
write lots of libraries (especially ‘dsl-y’ libraries) are in favor
of, and make heavy us of, class state of all kinds including
inheritable state - those who are against it are mainly writing their
own code and using other people’s libraries. the irony is that most
of the popular ruby libraries make use of inheritable class state:
just a short list

. merb
. ramaze
. sqlite-ruby
. main
. couchrest
. rubyigen
. action_mailer
. active_controller
. active_record
. extlib
. facets
. actionwebservice
. active_support
. zen test
. fattr
. etc…

so, if you like any of those libraries and what they have to offer,
you like class inheritable state being managed for you. in addition
i’d point out that anyone who likes esoteric concepts like ‘method
dispatch’ or ‘constant lookup’ also likes auto-magically maintained
class state. honestly it’s tiresome to see this idea still being
debated on ruby-talk with buggy code and claims that rolling your own
inheritance is easy (it isn’t - trust me - at least not in the general
case). therefore i’d for one, as author of dozens of libraries which
have rolled their own class var inheritance, like to offer my support
of your plea: there absolutely should be a ‘standard’ method of doing
this. i don’t know if that means being in core or that it should be a
library (possibly distributed with core), but you are quite correct in
observing that one has to be careful mixing methods with common names
like ‘inheritable’ into Object etc. a common, simple, and reusable
library would be a great help to many library writers and people that
claim that it wouldn’t be obviously aren’t writing a lot of libraries

  • at least not certain types of libraries.

i’ll leave you with my current favorite method of rolling class
inheritable attributes:

the fattr lib, avail as gem and at http://github.com/ahoward/fattr.
btw, anyone that thinks this is easy stuff should complete

http://rubyquiz.com/quiz67.html

although some of the complete answers are terse they are not
simple. the fattr code is based on the best answers.

cfp:~/src/git/fattr > cat a.rb
require ‘rubygems’
require ‘fattr’

class A
class << A
fattr(:x, :inheritable => true){ 42 }
end
end

class B < A; end

class C < B; end

p C.x
p B.x
p A.x
puts

B.x = 42.0

p C.x
p B.x
p A.x
puts

C.x! # force re-initialization from parent(s)

p C.x
p B.x
p A.x
puts

class K
end
class L < K
end
module M
fattr(:x, :inheritable => true){ 42 }
end
K.extend(M)

p L.x

cfp:~/src/git/fattr > ruby a.rb
42
42
42

42
42.0
42

42.0
42.0
42

42

regards.

On Sun, Oct 11, 2009 at 5:56 PM, David A. Black [email protected]
wrote:

I’m still not seeing why it’s so important that it be addressed in the
core. Of course I’d be glad to see @@ changed to something more useful
(Robert and I have been among the most vocal critics of class
variables over the years :slight_smile:

Here’s my vote for making @@ a syntax error. :slight_smile:

-greg

On Oct 12, 2009, at 1:47 PM, ara.t.howard wrote:

i’ll leave you with my current favorite method of rolling class
inheritable attributes:

the fattr lib, avail as gem and at http://github.com/ahoward/fattr.
btw, anyone that thinks this is easy stuff should complete

I was going to post a pointer to fattr but now I don’t have to.

I’ve used fattr for a few private projects and have found it quite
useful.

Gary W.

On 10/12/2009 06:45 PM, Gregory B. wrote:

On Sun, Oct 11, 2009 at 5:56 PM, David A. Black [email protected] wrote:

I’m still not seeing why it’s so important that it be addressed in the
core. Of course I’d be glad to see @@ changed to something more useful
(Robert and I have been among the most vocal critics of class
variables over the years :slight_smile:

Here’s my vote for making @@ a syntax error. :slight_smile:

+1!

robert

On Tue, 13 Oct 2009, ara.t.howard wrote:

disappointed in the responses you are getting from people.
write lots of libraries (especially ‘dsl-y’ libraries) are in favor
of, and make heavy us of, class state of all kinds including
inheritable state - those who are against it are mainly writing their
own code and using other people’s libraries. the irony is that most
of the popular ruby libraries make use of inheritable class state:
just a short list

I’m puzzled by the divisive tone of this. I think we’re all on the
same side – not necessarily of every topic that gets discussed here,
but of the basic principle that we’re all trying to help each other.

In any case – I’m not “against” class state. (I’m not even sure what
that would mean.) I am conservative about use-cases, even important
ones, making their way into the language as language-level constructs.
That’s what I’ve emphasized in this thread.

I think too that you’re conflating two distinct sub-issues: the
creation of language-level constructs, and the phenomenon of rewriting
the same code over and over. Obviously the latter is a bad idea, and
no one in this thread is suggesting otherwise. If I say that Ruby can
sustain a lot of quasi-language-feature-ish add-ons without having
them be put in the language, that does not imply that these should be
typed out by hand anew every time they’re going to be used.

David


The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com

David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)

Closer to what you want?

class A
def self.foo
instance_variable_defined?("@foo") ? @foo : foo!
end
def self.foo!
@foo = ancestors[1].foo if ancestors[1].respond_to?(:foo)
end
def self.foo=(x)
@foo = x
end
end

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs