Delegating class methods


#1

Hi all,

how would you forward calls from class methods to a class atribute?
Like in:

class Foo
@@hash = {}

def self.size
@@hash.size
end
end

I have to delegate a fairly large number of calls to an attribute. I’m
currently using method_missing, but I was wondering if there was a
cleaner way to do that as the method names are known at load time. I
didn’t find any using the standard library. Perhaps using some
metaprogramming.

Thanks!


#2

Arcadio Rubio garcía wrote:

Hi all,

how would you forward calls from class methods to a class atribute?

You can do the following:

class Foo
@one = 1
@two = 2
@three = 3

class << self
  attr_accessor :one, :two, :Tthee
end

end

(Why are you doing ‘@@’ instead of ‘@’?)


#3

On Mar 1, 2009, at 12:33 , abc wrote:

how would you forward calls from class methods to a class atribute?

I’m not thrilled that you have to use a class method to access the
attribute, but this works:

class Foo
extend SingleForwardable
def self.hash; @@hash ||= {}; end
def_delegators :hash, :size, :keys
end

p Foo.size
p Foo.keys

It’d be ideal if you could use :@@hash for the delegators line, but I
couldn’t get that to work easily.


#4

On Mar 1, 2009, at 22:08 , Albert S. wrote:

(Why are you doing ‘@@’ instead of ‘@’?)

Because, the OP wanted to use class vars, not class instance vars.


#5

BTW, there’s some glitch here. Let’s say you inherit from Foo:

I’m not sure this can really be called a glitch because that’s simply
the way self.instance-variables (or whatever their correct name is)
work. One solution would be to create a inherited class method that
copies the variables from the super class to the subclass.

class Foo
    @one = 1
    @two = 2
    @three = 3

    class << self
        attr_accessor :one, :two, :three

        def inherited(sub)
            sub.one = one
            sub.two = two
            sub.three = three
        end
    end
end

class Momo < Foo
end

Momo.one #=> 1

That’s cumbersome of course and it would be great if ruby had a
construct to do this automatically with having to define an inherited
hook.


Leo

The end is here -->


#6

I’m the OP. Thank you all for your replies.

Sorry if the question wasn’t clear enough. I wanted to register all
the instances of a class, so the original idea was to use a hash class
variable to do that.

Of course there are a number of gotchas if you want to make the code
concise using this approach, so an alternative solution is to declare
another class, make it a Singleton and use it for that purpose.

I’m not a seasoned Ruby programmer, but I think I was totally right in
the idea of using class variables (@@hash). I cannot see why some
people are surprised. I’d be very happy if somebody could shed some
light on the issue, because maybe I’m missing something…


#7

On Mar 2, 2009, at 03:05 , abc wrote:

I’m not a seasoned Ruby programmer, but I think I was totally right in
the idea of using class variables (@@hash).

No, using a class var there was totally appropriate.

In the case of your design, depending on what you’re actually trying
to accomplish by registering every instance, you can forgo the
registration hash and use:

ObjectSpace.each_object(YourClass) { |obj| … }

That only iterates live objects and also has the disadvantage of not
working in jruby or rubinius (yet?).


#8

On Mon, Mar 2, 2009 at 7:49 AM, Ryan D. removed_email_address@domain.invalid
wrote:

On Mar 1, 2009, at 22:08 , Albert S. wrote:

(Why are you doing ‘@@’ instead of ‘@’?)

Because, the OP wanted to use class vars, not class instance vars.
Yes but we do not allow this (easily) :wink:

Seriously OP are you sure you want class variables??
And if you’re answer is yes, let me ask you the following question:
Are you sure you want to use class variables??
And if you are not I am happily going further in explaining why ;).

Cheers
Robert


#9

Albert S. wrote:

You can do the following:

class Foo
@one = 1
@two = 2
@three = 3

class << self
  attr_accessor :one, :two, :Tthee
end

end

(Why are you doing ‘@@’ instead of ‘@’?)

BTW, there’s some glitch here. Let’s say you inherit from Foo:

class Momo < Foo
end

puts Momo.one # won’t print “1” !!!

The assignments to the attirbutes (in Foo’s body) are happening in Foo’s
bag, not in Momo’s bag


#10

On Mon, Mar 2, 2009 at 12:05 PM, abc removed_email_address@domain.invalid
wrote:

I’m not a seasoned Ruby programmer, but I think I was totally right in
the idea of using class variables (@@hash). I cannot see why some
people are surprised. I’d be very happy if somebody could shed some
light on the issue, because maybe I’m missing something…

oops sorry, you made your point already.
Well if you use class variables they will be shared by all your
subclasses, if that is what you want, perfect.

Often one does not want that behavior, hence the surprise ;), because
a superclass generally shall not know about its subclasses.
Implications on maintenance and reuse are heavy! But there are cases
where it is fine, just ponder the question carefully :slight_smile:

Cheers
Robert


#11

class Klass

extend Forwardable

def_delegators :@object :method1, :method2, :method3

def initialize
   @object = SomeKlass.new
end

end

end

=======================================================================
This email, including any attachments, is only for the intended
addressee. It is subject to copyright, is confidential and may be
the subject of legal or other privilege, none of which is waived or
lost by reason of this transmission.
If the receiver is not the intended addressee, please accept our
apologies, notify us by return, delete all copies and perform no
other act on the email.
Unfortunately, we cannot warrant that the email has not been
altered or corrupted during transmission.


#12

On Mon, Mar 2, 2009 at 4:35 PM, abc removed_email_address@domain.invalid
wrote:

I’m the OP. Thank you all for your replies.

Hello OP :slight_smile:

I’m not a seasoned Ruby programmer, but I think I was totally right in
the idea of using class variables (@@hash). I cannot see why some
people are surprised. I’d be very happy if somebody could shed some
light on the issue, because maybe I’m missing something…

There is a school of thought that eigenclass [1] instance variables
are generally preferred over @@class_variables. Folks coming to ruby
from other languages often miss the distinction but you’ll find many
exposés on this [2], including in the Pickaxe.

I personally like eigenclass variables - they provide all the
capability of class variables, fit elegantly into ruby’s object model
and follow all the rules of instance variables. So i don’t ever bother
with class vars.

It’s important to note this is completely orthogonal to the discussion
about whether it’s appropriate to use any class-level state at all.
That has been adequately addressed in this thread already, but it’s
possible some of the questioning about class variables may actually
have revolved around whether to use eigenclass variables instead.

Solidarity,
lasitha.

[1] a.k.a singleton class, metaclass, etc.
[2] http://tinyurl.com/3xeef2
http://tinyurl.com/2rnzrf
http://tinyurl.com/2thspb
http://tinyurl.com/2p3wc6


#13

On Mar 2, 2009, at 06:24 , lasitha wrote:

There is a school of thought that eigenclass [1] instance variables
are generally preferred over @@class_variables.

for the record, I’m NOT in this school of thought. I’m in the school,
across the street, lobbing water balloons at this school. I’ve never
ONCE had a design that needed class instance variables and I use class
variables a fair amount. The non-inheritability of class instance
variables is a deterrent imo.

Since this is a religious argument, I will not debate this topic on
the mailing list, so don’t bother arguing the matter.


#14

On Mar 2, 2009, at 9:24 AM, lasitha wrote:

There is a school of thought that eigenclass [1] instance variables
are generally preferred over @@class_variables. Folks coming to ruby
from other languages often miss the distinction but you’ll find many
exposés on this [2], including in the Pickaxe.

I personally like eigenclass variables - they provide all the
capability of class variables, fit elegantly into ruby’s object model
and follow all the rules of instance variables. So i don’t ever bother
with class vars.

I don’t think I’ve ever seen the term ‘eigenclass variables’ used in
this way. Every object has instance variables. Classes are objects
and so they have instance variables. There is no need to talk about
eigen classes (or the more common term, singleton classes) when you
are talking about alternatives to class variables.

The main confusion with Ruby class variables comes from:
– Ruby class variables have syntax similar to instance variables
but much different semantics
– Ruby class variables are assumed to be analogous to C++ class
variables (or Java class variables) but that is the wrong
analogy. Ruby instance variables of class objects is the more
appropriate comparison.

It would be nice if there was a common term for ‘instance variables
of class objects’ but ‘eigenclass variables’ isn’t it.

Gary W.


#15

On Mon, Mar 2, 2009 at 2:27 AM, Michael M.
removed_email_address@domain.invalid wrote:

def initialize
@object = SomeKlass.new
end
end

No, that would forward to an instance variable and only work with
Klass instances.

If the OP doesn’t mind using a singleton class variable instead of a
class variable [1], then we can still use forwardable:

class Foo
@hash = {}
class << self
extend Forwardable
def_delegators :@hash, :[], :[]=, :size
end
end

Foo[:bar] = ‘baz’
Foo.size #=> 1

Solidarity,
lasitha

[1] Generally a good idea anyway, right?


#16

On Mar 2, 2009, at 5:57 PM, Rick DeNatale wrote:

On Mon, Mar 2, 2009 at 5:05 PM, Gary W. removed_email_address@domain.invalid wrote:

It would be nice if there was a common term for ‘instance variables
of class objects’ but ‘eigenclass variables’ isn’t it.

I think that the common term is class instance variables, i.e. they
are
instance variables of a class object.

Sure that works but I also think it is the cause of some confusion
because ‘class instance variable’ is quite close to ‘class variable’,
yet (in Ruby) those are two very different things.


#17

On Mon, Mar 2, 2009 at 5:05 PM, Gary W. removed_email_address@domain.invalid wrote:

It would be nice if there was a common term for ‘instance variables
of class objects’ but ‘eigenclass variables’ isn’t it.

I think that the common term is class instance variables, i.e. they are
instance variables of a class object.

This is also what they are called in Smalltalk, which also has class
variables which are implemented as a name scope visible to a class and
its
subclasses, not often used, but when they are it’s mostly to define
named
constant values.


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


#18

On Tue, Mar 3, 2009 at 3:35 AM, Gary W. removed_email_address@domain.invalid wrote:

this way. Every object has instance variables. Classes are objects
and so they have instance variables. There is no need to talk about
eigen classes (or the more common term, singleton classes) when you
are talking about alternatives to class variables.

[…]

It would be nice if there was a common term for ‘instance variables
of class objects’ but ‘eigenclass variables’ isn’t it.

Retracted :). I was attempting to use a phrase that couldn’t be
mistaken for ‘class variable’ because i’d guessed the OP was not aware
of the difference. Actually i meant to write ‘eigenclass instance
variables’ which is possibly not as egregious.

In any case, i defer to those who’ve been rubyists much longer than i
and apologize for the confusion.

Solidarity,
lasitha.


#19

On Tue, Mar 3, 2009 at 5:10 AM, Gary W. removed_email_address@domain.invalid wrote:

On Mar 2, 2009, at 5:57 PM, Rick DeNatale wrote:

Sure that works but I also think it is the cause of some confusion
because ‘class instance variable’ is quite close to ‘class variable’,
yet (in Ruby) those are two very different things.
True, yet I think it is the best name I know so far :).
Rick’s right it exactly describes what they are. And one could
emphasize the issue by saying “instance variables of the class” if one
wants.
Cheers
Robert