Class atrr_accessor


#1

Why does this not work?

class Foo
self.class.attr_accessor :baz
end
TypeError: Foo is not a class
from (irb):19

I understand that the class << self idiom can be used to work around
this problem but I would like to understand why the above triggers such
an error and what is meant by it.

Thanks.


#2

On Dec 2, 2:16 pm, Oliver S. removed_email_address@domain.invalid wrote:

Why does this not work?

An ideology?

class Foo
self.class.attr_accessor :baz
end

TypeError: Foo is not a class
from (irb):19

class Module
public :attr_accessor
end

All fixed.

I understand that the class << self idiom can be used to work around
this problem but I would like to understand why the above triggers such
an error and what is meant by it.

Well, I think the idea is that you shouldn’t be changing a class’
interface from the “outside” ie. so willy-nilly. So you are required
to go “inside” to get the job done. Sort of a caution barrier. But it
does suck that this requires a second layer, eg. class << self, to get
there. I have tried a private #meta method in the past.

class Foo
meta.attr_accessor :baz
end

which works, though I’m not sure the term “meta” feels quite right.
I’ve avoided ever using it though because I know others would look at
it and think “what?”.

T.


#3

Oliver S. wrote:

Why does this not work?

class Foo
self.class.attr_accessor :baz
end
TypeError: Foo is not a class
from (irb):19

You must have miscopied your error message. I obtain

NoMethodError: private method `attr_accessor’ called for Class:Class

attr_accessor is a private method of Module, and as such cannot be
called directly with the dot notation. You can call it with send(), or
like this:

class Foo
self.class.instance_eval { attr_accessor :baz }
end

But nevermind, because this is not what you want!

Foo.baz = :qux
p Foo.baz # => :qux

class Bar
end

Bar.baz = 4
p Bar.baz # => 4

You’ve just added methods #baz and #baz= to every class. This is
because

class Foo
p(self.class == Class) # => true
end

You want the self << class construct that you mentioned, which is the
singleton class,

class Foo
class << self
attr_accessor :baz
end
end

When you said self.class, you were calling Object#class which tells you
the birth canal of an object. But many things can happen after birth,
and kids can end up really different from their parents! This
difference is described in the singleton class. It’s unique to the
object. Above, we are adding a method to Foo’s singleton class.

BTW there’s nothing special about “class << self”. You could also say,

class Foo
end
class << Foo
attr_accessor :baz
end

which is the same thing. “class << x” grabs the singleton class of x.

Hope this helps.