Class-level readers and writers

I’ve been working with the class attribute shortcuts that Hal introduced
in THE RUBY WAY:

class Class
def cattr_reader(*syms)
syms.each do |sym|
class_eval <<-EOS
if !defined? @@#{sym.id2name}
@@#{sym.id2name} = nil
end
def self.~{sym.id2name}
@@#{sym}
end
EOS
end
end

def cattr_writer(*syms)
	syms.each do |sym|
		class_eval <<-EOS
			if !defined? @@#{sym.id2name}
				@@#{sym.id2name} = nil
			end
			def self.#{sym.id2name}=(obj)
				@@#{sym.id2name} = obj
			end
		EOS
	end
end

def cattr_accessor(*syms)
	cattr_reader(*syms)
	cattr_writer(*syms)
end

end

I’m having a problem, however, in that classes that are inherited from
the ones in which I declare these attrs don’t seem to have them anymore.
Does anyone know how I can make my declared class attributes get
inherited?

Thanks,
Carl Youngblood

Hi –

I’ve been working with the class attribute shortcuts that Hal introduced
in THE RUBY WAY:

class Class
def cattr_reader(*syms)
syms.each do |sym|
class_eval <<-EOS
if !defined? @@#{sym.id2name}
@@#{sym.id2name} = nil
end
def self.~{sym.id2name}
^ typo here
I’m having a problem, however, in that classes that are inherited from
the ones in which I declare these attrs don’t seem to have them anymore.
Does anyone know how I can make my declared class attributes get
inherited?

I ran your code (except for the typo :slight_smile: with this added:

class A; cattr_accessor(:x); end
class B < A; end
B.x = 1
puts B.x

and it printed 1, so I think the error must be somewhere else.

(Just as a footnote, you can also use “normal” accessor shortcuts at
the class object level:

class A
class << self
attr_accessor :x
end
end

A.x = 1 # and so on

which is implemented with instance variables rather than class
variables, if for any reason that suits your purposes better.)

David

···

On Sat, 29 Nov 2003, Carl Youngblood wrote:


David A. Black
dblack@wobblini.net

David A. Black wrote:

(Just as a footnote, you can also use “normal” accessor shortcuts at
the class object level:

class A
class << self
attr_accessor :x
end
end

A.x = 1 # and so on

which is implemented with instance variables rather than class
variables, if for any reason that suits your purposes better.)

For the record, this is a cool trick. The reason it isn’t in
TRW is simply that I didn’t think of it.

The effect is subtly different, but it’s a good idiom.

Thanks, David…

Hal

(Just as a footnote, you can also use “normal” accessor shortcuts at
the class object level:

class A
class << self
attr_accessor :x
end
end

A.x = 1 # and so on

which is implemented with instance variables rather than class
variables, if for any reason that suits your purposes better.)

I’m still trying to figure out what this does, exactly. Is A.x an
instance variable or a class variable? If I have something like:

a = A.new

And I say:

a.x = 1

Is that modifying a class variable or an instance variable? Or does
that even work? I just want to make sure that the accessor will work if
called on either an instance or on the class itself.

Thanks,
Carl

Hi –

(Just as a footnote, you can also use “normal” accessor shortcuts at
the class object level:

class A
class << self
attr_accessor :x
end
end

A.x = 1 # and so on

which is implemented with instance variables rather than class
variables, if for any reason that suits your purposes better.)

I’m still trying to figure out what this does, exactly. Is A.x an
instance variable or a class variable? If I have something like:

a = A.new

And I say:

a.x = 1

Is that modifying a class variable or an instance variable? Or does
that even work? I just want to make sure that the accessor will work if
called on either an instance or on the class itself.

My example creates an instance variable… but the “instance” is the
Class object, A. It’s a case where one takes advantage of the
“classes are themselves objects” axiom. I’m creating private state
for the Class object itself. You could say that, at that moment, A is
wearing its “Object” hat, rather than its “Class” hat. It doesn’t
“know” that it is a Class, or can create instances; it just knows that
it’s an Object, and is therefore entitled to have instance variables
just like any other Object.

So, as with any other object, you can use those accessor methods to
maintain state:

A.x = 1
puts A.x # 1

etc.

And when you do create instances of A, those instances are separate
objects and have no automatic access to the instance variables of A.
By definition, two objects cannot directly share an instance
variable. The fact that one object is a Class and the other is an
instance of that class doesn’t change this; each is still an object,
with the right to either expose or not expose their instance
variables.

So if you want a class and its instances to share state, you have to
use a class variable (as in the Ruby Way example), or set up a
situation where the instances have access to the class’s own private
state:

class A
class << self
attr_accessor :x
end

def x
  self.class.x
end

def x=(y)
  self.class.x=(y)
end

end

A.x = 1
puts A.new.x # 1

But remember, if you do that, every instance of A will access the
same variables:

a = A.new
b = A.new
a.x = 2
puts b.x # 2

since #x and #x= are just wrappers for access to another object’s
instance variable @x (that other object being the Class object A).
So that’s probably not a great idea in most cases. Class variables
have their own quirks, though they’re scheduled to be a bit de-quirked
in 2.0.

David

···

On Sun, 30 Nov 2003, Carl Youngblood wrote:


David A. Black
dblack@wobblini.net

David A. Black wrote:

So that’s probably not a great idea in most cases. Class
variables have their own quirks, though they’re scheduled to
be a bit de-quirked in 2.0.

My understanding (not that my record in reading Matz 2.0
intention is anything I should be bragging about - not that
I mind, since I am feeling like a kid in a candy store:-)
was that Rite’s class variables will behave like today’s class
instance variables without the need of ``class attribute
accessors’'.

Personally I am actually in favor of getting ride of class variables
altogether and only use class attributes accessors + class instance
variables.

/Christoph

I sympathise. Maybe @@x could be syntax sugar for
self.class.instance_eval(“@x”), if you get my drift.

class Example
@x = 5

def meth
  @@x      # -> 5
end

end

There’s probably a really good reason why not; I’ve never really been
able to wrap my head around all the issue here.

Gavin

···

On Sunday, November 30, 2003, 8:59:15 AM, Christoph wrote:

David A. Black wrote:

So that’s probably not a great idea in most cases. Class
variables have their own quirks, though they’re scheduled to
be a bit de-quirked in 2.0.

My understanding (not that my record in reading Matz 2.0
intention is anything I should be bragging about - not that
I mind, since I am feeling like a kid in a candy store:-)
was that Rite’s class variables will behave like today’s class
instance variables without the need of ``class attribute
accessors’'.

Personally I am actually in favor of getting ride of class variables
altogether and only use class attributes accessors + class instance
variables.

I’m not sure if I’m understanding this correctly. Is the following in any way
related:

ruby-core:01787
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/1787

The short of it:

class X
a = 1
def a
@a # => 1
end
end

Or is that class local variable? Cause I’m not understand how @@a “will behave
like today’s class instance variables without the need of ``class attribute
accessors’'.”

Can you elaborate more?

-t0

···

On Saturday 29 November 2003 10:59 pm, Christoph wrote:

David A. Black wrote:

So that’s probably not a great idea in most cases. Class
variables have their own quirks, though they’re scheduled to
be a bit de-quirked in 2.0.

My understanding (not that my record in reading Matz 2.0
intention is anything I should be bragging about - not that
I mind, since I am feeling like a kid in a candy store:-)
was that Rite’s class variables will behave like today’s class
instance variables without the need of ``class attribute
accessors’'.

Hi –

David A. Black wrote:

So that’s probably not a great idea in most cases. Class
variables have their own quirks, though they’re scheduled to
be a bit de-quirked in 2.0.

My understanding (not that my record in reading Matz 2.0
intention is anything I should be bragging about - not that
I mind, since I am feeling like a kid in a candy store:-)
was that Rite’s class variables will behave like today’s class
instance variables without the need of ``class attribute
accessors’'.

Personally I am actually in favor of getting ride of class variables
altogether and only use class attributes accessors + class instance
variables.

I sympathise. Maybe @@x could be syntax sugar for
self.class.instance_eval(“@x”), if you get my drift.

class Example
@x = 5

def meth
  @@x      # -> 5
end

end

There’s probably a really good reason why not; I’ve never really been
able to wrap my head around all the issue here.

That would create a situation where it was awfully easy for one object
to get at another object’s instance variables, without the second
object having granted access. It’s already possible, as your example
shows, but I don’t think it’s the kind of thing one would want to
encourage with shortcuts (unless the object itself creates them).

I think the new incarnation of class variables might be handier than
[I’ve found] the current one [to be], though sometimes I also wish
they’d just disappear :slight_smile: I think part of the trouble people have with
the concept of Class objects having instance variables is that they
(wrongly but understandably) surmise that there must be some relation
or connection with class variables.

David

···

On Sun, 30 Nov 2003, Gavin Sinclair wrote:

On Sunday, November 30, 2003, 8:59:15 AM, Christoph wrote:


David A. Black
dblack@wobblini.net

Hello –

David A. Black wrote:

So that’s probably not a great idea in most cases. Class
variables have their own quirks, though they’re scheduled to
be a bit de-quirked in 2.0.

My understanding (not that my record in reading Matz 2.0
intention is anything I should be bragging about - not that
I mind, since I am feeling like a kid in a candy store:-)
was that Rite’s class variables will behave like today’s class
instance variables without the need of ``class attribute
accessors’'.

I’m not sure if I’m understanding this correctly. Is the following in any way
related:

I don’t think so.

[…]

Or is that class local variable? Cause I’m not understand how @@a “will behave
like today’s class instance variables without the need of ``class attribute
accessors’'.”

Matz’s description is:

  • class variables will be local to the class/module
  • if you need to access class variables from outside,
    define accessors

(See http://www.rubyist.net/~matz/slides/rc2003/mgp00020.html.)

So class vars will be able to do what they currently can’t do, namely
maintain state on a truly per-class basis (as opposed to
per-hierarchy). The difference between them and a class’s instance
variables, as I understand it, will be that the class variables are
visible from instances of the class.

David

···

On Sun, 30 Nov 2003, T. Onoma wrote:

On Saturday 29 November 2003 10:59 pm, Christoph wrote:


David A. Black
dblack@wobblini.net

To claim that there is no connection is a bit of stretch - as
you pointed out yourself the only difference between Rite’s
class variables and (today’s) instance is the additional visibility
of Rite’s class variables within class instances - this additional
visibility could easily achieved with accessor methods - which
has the BIG advantage that we could do without additional
Scoping rules of yet another special kind of variables (namely
class variables) reducing the overall complexity of the language.

This simplification might be especially welcome with the introduction
of yet another kind of variables a.k.a. ``class local variables’'.
I am sure you agree with me that there have been demonstrated
misunderstandings of (today’s) Ruby scoping rules not only by Nubies
but by seasoned practitioners as well - lets hope that Rite’s will
(okay, given Matz track record, I am certain things will be a lot
better:-) lift today’s visiblity (rules) fog.

/Christoph

Just as reminder here some possible 1.8.1 implementations
of a variety of nonhierarchical class accessor methods.

···

-----Original Message-----
From: David A. Black [mailto:dblack@wobblini.net]
Sent: Sunday, 30 November, 2003 03:29 AM
To: ruby-talk ML
Subject: Re: Class-level readers and writers

Hi –

On Sun, 30 Nov 2003, Gavin Sinclair wrote:

On Sunday, November 30, 2003, 8:59:15 AM, Christoph wrote:

David A. Black wrote:

So that’s probably not a great idea in most cases.
Class variables
have their own quirks, though they’re scheduled to be a bit
de-quirked in 2.0.

My understanding (not that my record in reading Matz 2.0
intention
is anything I should be bragging about - not that I mind,
since I am
feeling like a kid in a candy store:-) was that Rite’s class
variables will behave like today’s class instance
variables without
the need of ``class attribute accessors’'.

Personally I am actually in favor of getting ride of
class variables
altogether and only use class attributes accessors +
class instance
variables.

I sympathise. Maybe @@x could be syntax sugar for
self.class.instance_eval(“@x”), if you get my drift.

class Example
@x = 5

def meth
  @@x      # -> 5
end

end

There’s probably a really good reason why not; I’ve never
really been
able to wrap my head around all the issue here.

That would create a situation where it was awfully easy for
one object to get at another object’s instance variables,
without the second object having granted access. It’s
already possible, as your example shows, but I don’t think
it’s the kind of thing one would want to encourage with
shortcuts (unless the object itself creates them).

I think the new incarnation of class variables might be
handier than [I’ve found] the current one [to be], though
sometimes I also wish they’d just disappear :slight_smile: I think part
of the trouble people have with the concept of Class objects
having instance variables is that they (wrongly but
understandably) surmise that there must be some relation or
connection with class variables.


class T
class << self
attr_accessor :var
end
def var
self.class.var
end
def var=(rhs)
self.class.var= 2
end
end

T.new.var = 2
p T.new.var # 2

class A
var = nil

define_method(:var) {|| var }
define_method(:var=) {|rhs| var = rhs }
class << self
private
def inherited(sub)
sub.instance_eval {
var = nil
define_method(:var) {|| var }
define_method(:var=) {|rhs| var = rhs }
}

end
def initialize_copy(orig)
  super
   __var__ = nil
   define_method(:var) {|| __var__ }
   define_method(:var=) {|rhs| __var__ = rhs }
end

end
end

class B < A.clone
end
B.new.var = 2
p B.new.var

class AA
var = nil

define_method(:var) {|| var }
define_method(:var=) {|rhs| var = rhs }
class << self; self end.instance_eval {
define_method(:var) {|| var }
define_method(:var=) {|rhs| var = rhs }
}
class << self
private
def inherited(sub)
sub.instance_eval {
var = nil
define_method(:var) {|| var }
define_method(:var=) {|rhs| var = rhs }
class << self; self end.instance_eval {
define_method(:var) {|| var }
define_method(:var=) {|rhs| var = rhs }
}
}

end
def initialize_copy(orig)
  super
  __var__ = nil
  define_method(:var) {|| __var__ }
  define_method(:var=) {|rhs| __var__ = rhs }
  class << self; self end.instance_eval {
    define_method(:var) {|| __var__ }
    define_method(:var=) {|rhs| __var__ = rhs }
  }
end

end
end

class BB < AA.clone
end

BB.new.var = 2
p BB.new.var # 2
BB.var = 3
p BB.new.var # 3

Ruby.

Thanks David,

I’m actually starting to get dizzy 8-o. It would help, I think, if we lay
this down cold for all to understand. Could you fix the following yummy
class, to the best of your knowledge:

class ClassVariableSoup
class_local_var # scope is ?
def variables
local_var # scope is method
@class_instance_var # scope is instance/ancestry
@_local_class_instance_var # scope is instance
@@class_var # scope is class+instance/ancestry
@@_local_class_var # scope is class+instance
# others ?
end
$global_var # scope if everywhere
end

Much Obliged,
-t0

···

On Sunday 30 November 2003 12:11 pm, David A. Black wrote:

I don’t think so.

[…]

Or is that class local variable? Cause I’m not understand how @@a “will
behave like today’s class instance variables without the need of ``class
attribute accessors’'.”

Matz’s description is:

  • class variables will be local to the class/module
  • if you need to access class variables from outside,
    define accessors

(See http://www.rubyist.net/~matz/slides/rc2003/mgp00020.html.)

So class vars will be able to do what they currently can’t do, namely
maintain state on a truly per-class basis (as opposed to
per-hierarchy). The difference between them and a class’s instance
variables, as I understand it, will be that the class variables are
visible from instances of the class.

Hi,

I’ve been following this thread and the thread concerning the

class << self

construct with some interest, but not a thorough understanding.

If I’m considering these various remarks at least partly correctly (which is
highly questionable, since I’m both fairly new to Ruby and fairly rusty in
Objective-C), then it seems to me that these types of facilities would
greatly ease a coder’s ability to incorporate the sweet old Objective-C idea
of “class clusters”…and to make them even more dynamic, possibly tuning
class clusters at runtime, or even creating them from scratch.

Just my $0.02…and I hope I haven’t made a complete fool of myself…again:
new to Ruby, rusty in Obj-C, and any other disclaimers I can think of…

  • dan

self <<
“David A. Black” dblack@wobblini.net wrote in message
news:Pine.LNX.4.44.0311291817060.24317-100000@wobblini.net

···

Hi –

I think part of the trouble people have with
the concept of Class objects having instance variables is that they
(wrongly but understandably) surmise that there must be some relation
or connection with class variables.

David


David A. Black
dblack@wobblini.net

Hi –

From: David A. Black [mailto:dblack@wobblini.net]

I think the new incarnation of class variables might be
handier than [I’ve found] the current one [to be], though
sometimes I also wish they’d just disappear :slight_smile: I think part
of the trouble people have with the concept of Class objects
having instance variables is that they (wrongly but
understandably) surmise that there must be some relation or
connection with class variables.

To claim that there is no connection is a bit of stretch - as
you pointed out yourself the only difference between Rite’s
class variables and (today’s) instance is the additional visibility
of Rite’s class variables within class instances - this additional
visibility could easily achieved with accessor methods - which
has the BIG advantage that we could do without additional
Scoping rules of yet another special kind of variables (namely
class variables) reducing the overall complexity of the language.

What you’re describing is a similarity, not a connection :slight_smile: What I
mean is that there’s no interdependency, conceptually or in
implementation, between class vars and class instance vars. People
look for connections in trying to understand them, but they’re
actually best understood separately.

As for the new-style class variables compares with traditional
accessors defined on the Class object: the main difference I see is
that the accessors are presumably callable by anyone, whereas the new
class vars will be class-local (including instance method
definitions). It’s true that there’s been a lot of demand for this;
some of the class instance var confusion I’ve witnessed has arisen in
the course of searching for exactly this, and wishing that something
behaved this way. So it’s possible that once there’s a precise answer
to the question of how to scope something locally to a class, the
various constructs will get decoupled in people’s minds and therefore
easier to grasp.

This simplification might be especially welcome with the introduction
of yet another kind of variables a.k.a. ``class local variables’'.

I’m not sure what you meant here – isn’t that what the new class
variables are going to be?

David

···

On Sun, 30 Nov 2003, Christoph wrote:


David A. Black
dblack@wobblini.net

Hi –

I’m actually starting to get dizzy 8-o. It would help, I think, if we lay
this down cold for all to understand. Could you fix the following yummy
class, to the best of your knowledge:

class ClassVariableSoup
class_local_var # scope is ?
def variables
local_var # scope is method
@class_instance_var # scope is instance/ancestry

I think the definitive category is really just @instance_var, with the
question of whether the instance is a Class or not being irrelevant
(at least pre-2.0… see below).

@_local_class_instance_var   # scope is instance
@@class_var                        # scope is class+instance/ancestry
@@_local_class_var              # scope is class+instance
# others ?

end
$global_var # scope if everywhere
end

My current understanding, subject to correction, is:

local => current lexical scope
@instance => visible only when ‘self’ is what ‘self’ was at
the time the variable was created
@_instance => (2.0) visible to original ‘self’ (as above) and,
if original ‘self’ was a Class, to subclasses
of that class
@@class => class hierarchy, including inside instance method
definitions
=> (2.0) local to class where it’s defined; still visible
inside instance method definitions but not in
subclasses

(Note: for 2.0, which is @var and which is @_var hasn’t been decided.)

My least favorite of all of the proposed changes is definitely the
@var/@_var thing. It means that, for the first time, the concept of
an instance variable will not be completely unified. At the very
least, I don’t think something should be called an “instance variable”
if it isn’t private to the instance. (And then there’s that
underscore… :slight_smile:

David

···

On Mon, 1 Dec 2003, T. Onoma wrote:


David A. Black
dblack@wobblini.net

I'm not sure what you meant here -- isn't that what the new class
variables are going to be?

  http://www.rubyist.net/~matz/slides/rc2003/mgp00013.html

  @_var

Guy Decoux

David A. Black wrote:

What you’re describing is a similarity, not a connection :slight_smile:

I am not in the position to argue about fine point of the English
language with you, but a similarity is a “kind_of” (in the OO
sense) a connection in my orthographically challenged book:-)

What I mean is that there’s no interdependency, conceptually
or in implementation, between class vars and class instance
vars. People look for connections in trying to understand
them, but they’re actually best understood separately.

Maybe you right about the latter point - I just don’t know …

As for the new-style class variables compares with
traditional accessors defined on the Class object: the main
difference I see is that the accessors are presumably
callable by anyone, whereas the new class vars will be
class-local (including instance method definitions). It’s

You can can achieve the same effect by declaring the
class accessor methods (the instance version) protected

class A
var = nil
protected
define_method(:var) {|| var }
define_method(:var=) {|rhs| var= rhs }

end

Also I would not mind the introduction of ``class_protected’’
visibility attribute for class methods. Of course, it is bit of a
contradiction to champion an extra access modifier in order
to simplify visibility rules:-)

Example: Given declaration

class A; end
class B < A
def self.meth
puts “okay”
end
class_protected :meth
end

class B
def m
B.meth
end
End

class A
def foo
B.meth
end
end

B.new.foo # okay
A.new.foo # NoMethodError - called class protected …

/Christoph

My least favorite of all of the proposed changes is definitely the
@var/@_var thing. It means that, for the first time, the concept of
an instance variable will not be completely unified. At the very
least, I don't think something should be called an "instance variable"
if it isn't private to the instance. (And then there's that
underscore.... :slight_smile:

Well, if @_var make reference to what was initially, wrongly, called
"private instance variable" then renamed in "class local variable" then
it's private to the instance

Guy Decoux

Hi –

···

On Mon, 1 Dec 2003, ts wrote:

I’m not sure what you meant here – isn’t that what the new class
variables are going to be?

http://www.rubyist.net/~matz/slides/rc2003/mgp00013.html

@_var

Oh right. I keep forgetting those because I wish they would go away
:slight_smile: (Sorry Matz, if you’re reading; I just personally don’t like magic
behavior depending on the name of a variable, in any language.)

David


David A. Black
dblack@wobblini.net

I wrote:

Also I would not mind the introduction of ``class_protected’’
visibility attribute for class methods. Of course, it is bit

I guess this should be called “access attribute”

of a contradiction to champion an extra access modifier in
order to simplify visibility rules:-)

/Christoph