Forum: Ruby Quick syntax question

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Gregory S. (Guest)
on 2006-04-10 19:01
(Received via mailing list)
Consider the following three class definitions:

class Foo
  def self.bar
    @@bar
  end
  def self.bar=(val)
    @@bar = val
  end
end

class Foo
  class << self
    def bar
      @@bar
    end
    def bar=(val)
      @@bar = val
    end
  end
end

class Foo
  class << self
    attr_accessor :bar
  end
end

Am I correct in believing that they are equivalent? If not, how do they
differ?

--Greg
Logan C. (Guest)
on 2006-04-10 19:22
(Received via mailing list)
On Apr 10, 2006, at 11:00 AM, Gregory S. wrote:

> Am I correct in believing that they are equivalent? If not, how do
> they
> differ?

Yes, semantically anyway. (I remember seeing somewhere that
attr_accessor has some performance tricks, but the effect is the same)
Austin Z. (Guest)
on 2006-04-10 19:26
(Received via mailing list)
On 4/10/06, Gregory S. <removed_email_address@domain.invalid> wrote:
>
>
> class Foo
>   class << self
>     attr_accessor :bar
>   end
> end
>
> Am I correct in believing that they are equivalent? If not, how do they
> differ?

They are not equivalent. The first two are the same, but the third
will be accessing @bar, not @@bar. (Try it in IRB and you'll see.)

-austin
Logan C. (Guest)
on 2006-04-10 19:29
(Received via mailing list)
On Apr 10, 2006, at 11:24 AM, Austin Z. wrote:

> They are not equivalent. The first two are the same, but the third
> will be accessing @bar, not @@bar. (Try it in IRB and you'll see.)

Oops, my eyes musta glazed over the double @-signs. Austin is correct.
pat eyler (Guest)
on 2006-04-10 19:41
(Received via mailing list)
On 4/10/06, Austin Z. <removed_email_address@domain.invalid> wrote:
> > end
> > end
> >

[different third class deleted]

> > Am I correct in believing that they are equivalent? If not, how do they
> > differ?
>
> They are not equivalent. The first two are the same, but the third
> will be accessing @bar, not @@bar. (Try it in IRB and you'll see.)
>


Interestingly though, the the sexps representing the AST for the first
two
classes are pretty different looking:

[[:class,
  :Example,
  :Object,
  [:defn,
   :example,
   [:scope,
    [:block,
     [:args],
     [:defs, [:self], :bar, [:scope, [:block, [:args], [:cvar,
:@@bar]]]],
     [:defs,
      [:self],
      :bar=,
      [:scope, [:block, [:args, :val], [:cvasgn, :@@bar, [:lvar,
:val]]]]]]]]]

vs.

[[:class,
  :Example,
  :Object,
  [:defn,
   :example,
   [:scope,
    [:block,
     [:args],
     [:sclass,
      [:self],
      [:scope,
       [:block,
        [:defn, :bar, [:scope, [:block, [:args], [:cvar, :@@bar]]]],
        [:defn,
         :bar=,
         [:scope,
          [:block, [:args, :val], [:cvasgn, :@@bar, [:lvar,
:val]]]]]]]]]]]]]
Mark V. (Guest)
on 2006-04-10 22:15
(Received via mailing list)
On 4/10/06, Austin Z. <removed_email_address@domain.invalid> wrote:
> > end
> > end
> They are not equivalent. The first two are the same,
That's good to know. I can't see any reason to prefer the second over
the first. It's a lot more noisy.
Austin Z. (Guest)
on 2006-04-10 22:21
(Received via mailing list)
On 4/10/06, Mark V. <removed_email_address@domain.invalid> wrote:
> That's good to know. I can't see any reason to prefer the second over
> the first. It's a lot more noisy.

When you're defining a lot of class methods, class << self makes
sense. One or two? Then you may as well use def self.foo if you can.

-austin
unknown (Guest)
on 2006-04-10 22:24
(Received via mailing list)
Hi --

On Tue, 11 Apr 2006, Mark V. wrote:

>>>   end
>>>   end
>>
>> They are not equivalent. The first two are the same,
>
> That's good to know. I can't see any reason to prefer the second over
> the first. It's a lot more noisy.

There's a subtle difference between the two ways of defining a
singleton method, though:

X = 1

class C
end

class << C
   X = 2
end

class << C
   def x
     X
   end
end

def C.x2
   X
end

p C.x          # 2 (the X from C's singleton class)
p C.x2         # 1 (the X from outer scope)


David

--
David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!
http://www.manning.com/black
Mark V. (Guest)
on 2006-04-10 22:31
(Received via mailing list)
On 4/10/06, Austin Z. <removed_email_address@domain.invalid> wrote:
> On 4/10/06, Mark V. <removed_email_address@domain.invalid> wrote:
> > That's good to know. I can't see any reason to prefer the second over
> > the first. It's a lot more noisy.
>
> When you're defining a lot of class methods, class << self makes
> sense. One or two? Then you may as well use def self.foo if you can.

Just expressing personal preference ... even in that case I prefer the
first form (using self. on each class method). That way when I look at
a method, it's immediate obvious that it's a class method if the name
starts with "self.". Otherwise I have to lookup upward in the code to
see if the method is contained in a "class << self"
unknown (Guest)
on 2006-04-10 22:52
(Received via mailing list)
On Tue, 11 Apr 2006, Mark V. wrote:

>>>   end
>>>   end
>>
>> They are not equivalent. The first two are the same,
>
> That's good to know. I can't see any reason to prefer the second over
> the first. It's a lot more noisy.

class C
   class << self  # 100% class stuff that is hard to do with 'Class.'
below

     def a_class_method() end

     alias one_class_method to_another

     define_method('another_class_method'){ 42 }

     %w( a b c d e f g ).each{|of_seven_class_attributes| attr
of_seven_class_attributes}

     undef a_blown_away_class_method

     remove_method 'blow_this_method_of_off_the_class'

     undef_method 'stop_responding_to_this_class_method_at_all'

     public 'a'  # the class method
   end
end

'class << self' is 100 time more consistent and, as soon as you break
one
method 100 times less noisy imho.

regards.

-a
unknown (Guest)
on 2006-04-10 22:58
(Received via mailing list)
Hi --

On Tue, 11 Apr 2006, removed_email_address@domain.invalid wrote:

>>>>   def self.bar=(val)
>>>>       @@bar = val
>>>> Am I correct in believing that they are equivalent? If not, how do they
>    def a_class_method() end
>    remove_method 'blow_this_method_of_off_the_class'
>
>    undef_method 'stop_responding_to_this_class_method_at_all'
>
>    public 'a'  # the class method

and:

     self

:-)


>  end
> end
>
> 'class << self' is 100 time more consistent and, as soon as you break one
> method 100 times less noisy imho.


David

--
David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!
http://www.manning.com/black
Mark V. (Guest)
on 2006-04-10 23:16
(Received via mailing list)
On 4/10/06, removed_email_address@domain.invalid 
<removed_email_address@domain.invalid> wrote:
> >>>   def self.bar=(val)
> >>>       @@bar = val
> >>> Am I correct in believing that they are equivalent? If not, how do they
>      def a_class_method() end
>
>      undef_method 'stop_responding_to_this_class_method_at_all'
>
>      public 'a'  # the class method
>    end
> end
>
> 'class << self' is 100 time more consistent and, as soon as you break one
> method 100 times less noisy imho.

Thanks Ara!  I was only thinking about defining class methods.  You
gave me lots to consider that I wasn't before.

I do think it's a weird syntax though. It's a class definition inside
a class definition, but it isn't defining a nested class like many
Ruby beginners might guess at first glance.
unknown (Guest)
on 2006-04-11 00:21
(Received via mailing list)
On Tue, 11 Apr 2006, Mark V. wrote:

> Thanks Ara!  I was only thinking about defining class methods.  You gave me
> lots to consider that I wasn't before.
>
> I do think it's a weird syntax though. It's a class definition inside a
> class definition, but it isn't defining a nested class like many Ruby
> beginners might guess at first glance.

yeah.  no one said it wasn't weird  ;-)


i've come to think of

   'class << self'

as

   'append to my class'

if that helps any.

cheers.

-a
Stephen B. (Guest)
on 2006-04-11 00:27
(Received via mailing list)
I'm new to Ruby and I'd like to be able to derive from a class and
define a new class variable to replace a class variable in the parent
class -- however I also want the original class to have access to
it's original class variable.

Here's my simple test program:

class Klass
  cattr_accessor :prefix
   @@prefix = ''
   def Klass.show(string)
     puts @@prefix + string
   end
end

class DerivedKlass < Klass
   cattr_accessor :prefix
   @@prefix = ''
end

Klass.prefix = "123"
Klass.show("abc") # => "123abc"
DerivedKlass.prefix = "789"
DerivedKlass.show("abc")# => "789abc"
Klass.show("abc") # => "789abc"

I'd like Klass.show("abc") to instead produce "123abc".

The reason I'd think I'd like to do it this way is that I need to
change how ActiveRecord works. Here's my problem:

I have 2 different ActiveRecord connections open and one of them is
to a shared database so I set the following class variable:

ActiveRecord::Base.table_name_prefix = 'myapp_'

So while I refer to the table 'users' in my code in the database the
table is actually named 'myapp_users'.

However the other connection is to a legacy database and I need to
access the tables in this database without the table_name_prefix.

If this can't be done perhaps I could do something in DerivedKlass so
that any accesses to it's actual or inherited object methods save
Klass.prefix, replace it, and restore it? Of course the restoration
would have to work for both normal program flow and for an error.
This sounds uglier to me.

Thanks for any advice.
unknown (Guest)
on 2006-04-11 01:52
(Received via mailing list)
Hi --

On Tue, 11 Apr 2006, removed_email_address@domain.invalid wrote:

>
>
> i've come to think of
>
>  'class << self'
>
> as
>
>  'append to my class'
>
> if that helps any.

Interesting -- I think of the << as associating the other way :-)

class << obj   # yank the singleton class out of obj


David

--
David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 1!
http://www.manning.com/black
Stephen B. (Guest)
on 2006-04-11 02:39
(Received via mailing list)
I realized after working more that cattr_accessor was defined in the
core extensions in ActiveSupport as an extension of the class Class.
I now working on understanding how this works:

# Extends the class object with class and instance accessors for
class attributes,
# just like the native attr* accessors for instance attributes.
class Class # :nodoc:
   def cattr_reader(*syms)
     syms.flatten.each do |sym|
       class_eval(<<-EOS, __FILE__, __LINE__)
         unless defined? @@#{sym}
           @@#{sym} = nil
         end

         def self.#{sym}
           @@#{sym}
         end

         def #{sym}
           @@#{sym}
         end
       EOS
     end
   end

   def cattr_writer(*syms)
     syms.flatten.each do |sym|
       class_eval(<<-EOS, __FILE__, __LINE__)
         unless defined? @@#{sym}
           @@#{sym} = nil
         end

         def self.#{sym}=(obj)
           @@#{sym} = obj
         end

         def #{sym}=(obj)
           @@#{sym} = obj
         end
       EOS
     end
   end
Stephen B. (Guest)
on 2006-04-11 03:58
(Received via mailing list)
Here's a copy of my test case without using the ActiveSuppoprt's
cattr_accessor method:

class Klass
   def prefix
     @@prefix
   end
   def prefix=(value)
     @@prefix=value
   end
   def Klass.show(string)
     puts @@prefix + string
   end
end

puts Klass.prefix.object_id

class DerivedKlass < Klass
   def prefix
     @@prefix
   end
   def prefix=(value)
     @@prefix=value
   end
end

puts DerivedKlass.prefix.object_id

Klass.prefix = "123"
Klass.show("abc") # => "123abc"
DerivedKlass.prefix = "789"
DerivedKlass.show("abc")# => "789abc"
Klass.show("abc") # => "789abc"

which produces:

2968188
2968188
123abc
789abc
789abc

I'd like to be able to create a class variable that will apply to all
objects made from that class and ALSO create a derived class with a
different class variable that is used in objects created from the
derived class WITHOUT affecting the class variable defined in the
original class.

It isn't obvious to me how to do this using class variables so either
I'm missing something or there is another way to solve this
programming problem. I'm going to look into how Ruby creates class
variables.
Andrew T. (Guest)
on 2006-04-11 19:20
Stephen B. wrote:

> I'd like to be able to create a class variable that will apply to all
> objects made from that class and ALSO create a derived class with a
> different class variable that is used in objects created from the
> derived class WITHOUT affecting the class variable defined in the
> original class.

Try a class instance  variable vs a class variable:

class C
    @somevar = 'x'
    class << C
        def somevar
            @somevar
        end

        def somevar=(var)
            @somevar=var
        end
    end
end

Its not as easily accessible as a class variable (only accessible from
class methods) and you'd have to initialize it to something in derived
classes (otherwise it's nil) but its non-inherited. Not totally what you
want, but maybe it'll help.

Andrew
unknown (Guest)
on 2006-04-11 19:53
(Received via mailing list)
On Wed, 12 Apr 2006, Andrew T. wrote:

> class C
> end
>
> Its not as easily accessible as a class variable (only accessible from
> class methods) and you'd have to initialize it to something in derived
> classes (otherwise it's nil) but its non-inherited. Not totally what you
> want, but maybe it'll help.
>
> Andrew

this is one of the things traits.rb solves:

   harp:~ > yes | sudo gem install traits.rb > /dev/null 2>&1


   harp:~ > cat a.rb
   require 'traits'

   class Base
     class_trait 'a' => 42
   end

   class Derived < Base
   end

   class Derived2 < Base
     a 42.0
   end

   p Base.a
   p Derived.a
   p Derived2.a


   harp:~ > ruby a.rb
   42
   42
   42.0

the inheritence is smart and allows overriding.

regards.

-a
This topic is locked and can not be replied to.