Adding in class attribute with a Module

you can do it with one:

   harp:~ > cat a.rb
   module M
     def a
       self
     end
     def self.included other
       other.extend self
       super
     end
   end

   class C
     include M
   end

   p C.a
   p C.new.a

   harp:~ > ruby a.rb
   C
   #<C:0xb75d0a20>

regards.

-a

···

On Tue, 11 Apr 2006, Sam Roberts wrote:

On Tue, Apr 11, 2006 at 02:46:24AM +0900, zdennis wrote:

Is there an easy way to extend classes with both class and object
methods at the same time?

  irb(main):010:1* def self.included( clazz )
  irb(main):011:2> clazz.extend( ClassLevelAddons )
  irb(main):012:2> end
  irb(main):013:1> end

The above lets M take care of the work, so your class doesn't have to
think about it. This is the method that Robert Klemme was refering to,
Module::included

I was hoping that I was missing some clever way to do it with just one
module. Guess not. But the self.included hook is a good idea. The two
modules become an implementation detail, and thats good enough.

--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

dblack@wobblini.net wrote:

Hi --

James Britt wrote:

Actually I wrote this bit :slight_smile:

I don't like the sprawl of the concept of
an "attribute" of a class-hierarchy-plus-instances-of-those-classes.

I think this is what you are referring to David, and I think it is
strange to:

zdennis@lima:~$ irb
irb(main):001:0> class A
irb(main):002:1> @@myvar = 5
irb(main):003:1> class << self ; @myvar = 10 ; end
irb(main):004:1> end
=> 10
irb(main):005:0> A.instance_variables
=>
irb(main):006:0> A.class_variables
=> ["@@myvar"]
irb(main):007:0> a = class A ; class << self ; self ; end ; end
=> #<Class:A>
irb(main):008:0> a.instance_variables
=> ["@myvar"]
irb(main):009:0> a.instance_eval "@myvar"
=> 10
irb(main):010:0> A.module_eval "@@myvar"
=> 5
irb(main):011:0>

It seems like, @@myvar and @myvar should refer to the same reference
point. I would expect @@ to signify a class level attribute, which
is actually an instance attribute on the class itself. In my head
that makes sense.

I disagree. If @@myvar is just the instance variable @myvar of some
class object, then it would presumably have exactly the same scope as
that instance variable -- in which case, there's no reason for it to
exist. If it's visible to other objects (i.e., when 'self' is
something other than the class object), then it isn't the same as an
instance variable anyway.

I wouldn't want to see any crossover between class variables and
instance variables. A class object's instance variables are strictly
the business of the class in its "civilian" capacity as a regular
object. Class variables, on the other hand, are a special case.
The two things are really not related conceptually at all.

I see what you are saying, if there was crossover, then anything dealing with the class as an object, in it's "civilian" state as
you put it would essentially become a class variable which it is not.

On a implementation note, we achieve the same end result don't we (focus on the *end* part of that statement, and nothing in
between)?

  class C
     class << self ; attr_accessor :m ; end
  end

  class D
     def self.m ; @@m ; end
     def self.m=arg ; @@m = arg ; end
  end

- From a usage perspective as the end-user of the langauge nothing changes:

  irb(main):025:0> C.m = 5
  => 5
  irb(main):026:0> C.m
  => 5
  irb(main):027:0> D.m = 10
  => 10
  irb(main):028:0> D.m
  => 10

It definitely seems that if the two are to stay separate by implementation and conceptualization that it would nice to have those
class accessor methods, which don't invade the class's civilian state. I use that as a shortcut to writing my own accessors...
   class << self ; attr_* :foo ; end

Saves me typing in light of a class get/set shortcut existing...

Zach

···

On Tue, 11 Apr 2006, zdennis wrote:

I'm coming into this thread late, but I think I'm missing something here. What's wrong with this?

module Foo
    attr_accessor :meth_a
end

class Bar
    include Foo
    extend Foo
end

p Bar.meth_a # nil
Bar.meth_a = 'test'
p Bar.meth_a # 'test'

bar = Bar.new
p bar.meth_a # nil
bar.meth_a = 'test'
p bar.meth_a # 'test'

Regards,

Dan

···

ara.t.howard@noaa.gov wrote:

On Tue, 11 Apr 2006, Sam Roberts wrote:

On Tue, Apr 11, 2006 at 02:46:24AM +0900, zdennis wrote:

Is there an easy way to extend classes with both class and object
methods at the same time?

  irb(main):010:1* def self.included( clazz )
  irb(main):011:2> clazz.extend( ClassLevelAddons )
  irb(main):012:2> end
  irb(main):013:1> end

The above lets M take care of the work, so your class doesn't have to
think about it. This is the method that Robert Klemme was refering to,
Module::included

I was hoping that I was missing some clever way to do it with just one
module. Guess not. But the self.included hook is a good idea. The two
modules become an implementation detail, and thats good enough.

you can do it with one:

  harp:~ > cat a.rb
  module M
    def a
      self
    end
    def self.included other
      other.extend self
      super
    end
  end

  class C
    include M
  end

  p C.a
  p C.new.a

  harp:~ > ruby a.rb
  C
  #<C:0xb75d0a20>

regards.

-a

Hi --

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi --

James Britt wrote:

Actually I wrote this bit :slight_smile:

I don't like the sprawl of the concept of
an "attribute" of a class-hierarchy-plus-instances-of-those-classes.

I think this is what you are referring to David, and I think it is
strange to:

zdennis@lima:~$ irb
irb(main):001:0> class A
irb(main):002:1> @@myvar = 5
irb(main):003:1> class << self ; @myvar = 10 ; end
irb(main):004:1> end
=> 10
irb(main):005:0> A.instance_variables
=>
irb(main):006:0> A.class_variables
=> ["@@myvar"]
irb(main):007:0> a = class A ; class << self ; self ; end ; end
=> #<Class:A>
irb(main):008:0> a.instance_variables
=> ["@myvar"]
irb(main):009:0> a.instance_eval "@myvar"
=> 10
irb(main):010:0> A.module_eval "@@myvar"
=> 5
irb(main):011:0>

It seems like, @@myvar and @myvar should refer to the same reference
point. I would expect @@ to signify a class level attribute, which
is actually an instance attribute on the class itself. In my head
that makes sense.

I disagree. If @@myvar is just the instance variable @myvar of some
class object, then it would presumably have exactly the same scope as
that instance variable -- in which case, there's no reason for it to
exist. If it's visible to other objects (i.e., when 'self' is
something other than the class object), then it isn't the same as an
instance variable anyway.

I wouldn't want to see any crossover between class variables and
instance variables. A class object's instance variables are strictly
the business of the class in its "civilian" capacity as a regular
object. Class variables, on the other hand, are a special case.
The two things are really not related conceptually at all.

I see what you are saying, if there was crossover, then anything dealing with the class as an object, in it's "civilian" state as
you put it would essentially become a class variable which it is not.

On a implementation note, we achieve the same end result don't we (focus on the *end* part of that statement, and nothing in
between)?

class C
    class << self ; attr_accessor :m ; end
end

class D
    def self.m ; @@m ; end
    def self.m=arg ; @@m = arg ; end
end

- From a usage perspective as the end-user of the langauge nothing changes:

irb(main):025:0> C.m = 5
=> 5
irb(main):026:0> C.m
=> 5
irb(main):027:0> D.m = 10
=> 10
irb(main):028:0> D.m
=> 10

Sure -- it's just two ways to implement the method. But I wouldn't
call the second one an attribute, because:

   class E < D
     @@m = 12
   end

so E (a different object from D) can directly, and without being
"impolite" (i.e., no instance_eval, etc.), manipulate the same
variable as the one storing the value in D.m. And instances of D also
have direct, non-invasive access to that same @@m.

It definitely seems that if the two are to stay separate by
implementation and conceptualization that it would nice to have
those class accessor methods, which don't invade the class's
civilian state. I use that as a shortcut to writing my own
accessors...
  class << self ; attr_* :foo ; end

Saves me typing in light of a class get/set shortcut existing...

I would actually expect something called cattr_* to work like that,
rather than the way the Rails one works. Whether or not it's
necessary is another question :slight_smile: But as a shortcut-shortcut, it
could make sense.

David

···

On Tue, 11 Apr 2006, zdennis wrote:

dblack@wobblini.net wrote:

On Tue, 11 Apr 2006, zdennis wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!

nothing at all. i just tend to forget

   extend Foo

later in my code.

plus it can violate dry when you start doing

   class Button
     include Colors
     extend Colors
   end

   class Window
     include Colors
     extend Colors
   end

   class Panel
     include Colors
     extend Colors
   end

etc. easier to do

   module Colors
     def included
       ...
     end
   end

one time IMHO. OTOH this might confuse someone. you certainly right though.

cheers.

-a

···

On Tue, 11 Apr 2006, Daniel Berger wrote:

I'm coming into this thread late, but I think I'm missing something here. What's wrong with this?

module Foo
  attr_accessor :meth_a
end

class Bar
  include Foo
  extend Foo
end

p Bar.meth_a # nil
Bar.meth_a = 'test'
p Bar.meth_a # 'test'

bar = Bar.new
p bar.meth_a # nil
bar.meth_a = 'test'
p bar.meth_a # 'test'

Regards,

Dan

--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama

Daniel Berger wrote:

I'm coming into this thread late, but I think I'm missing something
here. What's wrong with this?

module Foo
   attr_accessor :meth_a
end

class Bar
   include Foo
   extend Foo
end

p Bar.meth_a # nil
Bar.meth_a = 'test'
p Bar.meth_a # 'test'

bar = Bar.new
p bar.meth_a # nil
bar.meth_a = 'test'
p bar.meth_a # 'test'

I was thinking that Sam wasn't looking for the same interface at both the instance and class levels. I was thinking he wanted the
equivalent of if including Modules also brought in the module levels methods.

module M
  def self.foo
     "foo"
  end

  def bar
    "bar"
  end
end

class A
  include M
end

A.foo # => "foo"
A.new.bar => "bar"

Given the above code is what I think Sam was hoping to achieve, that's why I focused on giving the example of getting that
functionality using include/extend.

Zach