Style question: using 'block_given?'

I’m new to Ruby, and want to know what The Best Way To Do It is…

I’ve been playing around with a simple Tree class, trying to get a handle
on ‘yield’ and iterators in general, which my Perl knowledge doesn’t help
with so much…

class Tree
include Enumerable
@data # The data
@kids # The (optional) children
attr :data, :kids

def initialize(data)
@data = data
@kids = []
end
end

Say I’d like to traverse the tree depth-first. I’d also like to have my
depthFirst method either use the given block or return an array, as usage
indicates, much like String#scan does.

def depthFirst
if block_given?
yield self
@kids.each {|k| k.depthFirst {|x| yield x}}
else
a = []
a << self
@kids.each {|k| a += k.depthFirst}
return a
end
end

My questions:

  • Is this even the right approach to doing this?
  • The {|x| yield x} looks weird to me; not that I can think of a better
    way to do it, but it seems like the sort of thing that’s…ugly.

Sorry to post such a newbie question; ‘yield’ is proving a little difficult
for me to get my head around.

Bill Dueber * Ph.D. candidate, Instructional Systems Technology, IU *
Graduate Assistant, IU Bloomington Educational Studies and Testing

I'm new to Ruby, and want to know what The Best Way To Do It is...

I've been playing around with a simple Tree class, trying to get a handle
on 'yield' and iterators in general, which my Perl knowledge doesn't help
with so much...

A couple of asides:

class Tree
  include Enumerable
  @data # The data
  @kids # The (optional) children

You don't need to put @data or @kids; the assignments in 'initialize' are
all you need. (It doesn't make much sense to refer to instance variables
outside of a method)

  attr :data, :kids

should be 'attr_accessor :data, :kids'

What you have written equates to
    attr :data, true
which in turn equates to
    attr_accessor :data

(personally I think 'attr' should have the behaviour you expect, and the
boolean version be called something else :slight_smile:

  def initialize(data)
    @data = data
    @kids =
  end
end

Looks good so far.

Say I'd like to traverse the tree depth-first. I'd also like to have my
depthFirst method either use the given block or return an array, as usage
indicates, much like String#scan does.

def depthFirst
   if block_given?
     yield self
     @kids.each {|k| k.depthFirst {|x| yield x}}
   else
     a =
     a << self
     @kids.each {|k| a += k.depthFirst}
     return a
   end
end

My questions:
- Is this even the right approach to doing this?
- The {|x| yield x} looks weird to me; not that I can think of a better
   way to do it, but it seems like the sort of thing that's...ugly.

You can take the passed block and bind it as a named parameter using '&'

So with a few minor tweaks, your class becomes:

  class Tree
    include Enumerable
    attr_accessor :data, :kids
    def initialize(data=nil)
      @data = data
      @kids =
    end
    def depthFirst(&block)
      if block_given?
        yield self
        @kids.each {|k| k.depthFirst &block}
      elsif @kids.empty?
        self.data
      else
        result = [self.data]
        result << @kids.collect {|k| k.depthFirst}
      end
    end
  end

  a = Tree.new("top")
  a.kids << Tree.new("one")
  a.kids << Tree.new("two")
  a.kids << Tree.new("three")
  a.kids[1].kids << Tree.new("grandchild1")
  a.kids[1].kids << Tree.new("grandchild2")

  a.depthFirst { |k| puts k.data }
       
  puts a.depthFirst.inspect

Without a block I decided to return the tree as a nested array, but you can
modify the code to flatten it, or use Array#flatten on the result.

You need to give your class an 'each' operator for Enumerable to be useful;
depthFirst would be a good candidate for that.

Regards,

Brian.

···

On Sat, Feb 22, 2003 at 05:00:44AM +0900, Bill Dueber wrote:

  else
    result = [self.data]
    result << @kids.collect {|k| k.depthFirst}
  end

Or a bit more minimalist:

  else
    [@data] + @kids.collect {|k| k.depthFirst}
  end

This is something you will find about Ruby: you keep thinking of more
compact and clear ways to write the same thing. And if you can’t think of a
compact and clear way of writing it, then you write a class to do that
operation for you :slight_smile:

Regards,

Brian.

This is the class instance variable police. Freeze! Keine Bewegung!

:wink:

It is a meaningful thing to do but it’s not what he wants anyway.

For one legitimate use of class instance variables, see
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/62292

···

On Sat, Feb 22, 2003 at 06:05:23AM +0900, Brian Candler wrote:

On Sat, Feb 22, 2003 at 05:00:44AM +0900, Bill Dueber wrote:

I’m new to Ruby, and want to know what The Best Way To Do It is…

I’ve been playing around with a simple Tree class, trying to get a handle
on ‘yield’ and iterators in general, which my Perl knowledge doesn’t help
with so much…

A couple of asides:

class Tree
include Enumerable
@data # The data
@kids # The (optional) children

You don’t need to put @data or @kids; the assignments in ‘initialize’ are
all you need. (It doesn’t make much sense to refer to instance variables
outside of a method)


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

(It is an old Debian tradition to leave at least twice a year …)
– Sven Rudolph

This is the class instance variable police. Freeze! Keine Bewegung!

:wink:

It's a fair cop :slight_smile: I had a hard time getting my head round this one:

- Class variables (@@data) are fine.

- Instance variables in a module are fine: mix it into a class, and
  instances of that class get those instance variables too

- But @data as a class instance variable? You can't even refer to it,
  except from within a class method. (Unlike a class variable, @@data,
  which you can use within a normal instance method)

It looks like something which the language has by accident more than by
design :slight_smile:

Regards,

Brian.

It helps to keep in mind that classes in Ruby are objects as well (instances
of Class). So @data there is an instance variable of an object of type
Class. With all interesting consequences.

Gennady.

···

----- Original Message -----
From: “Brian Candler” B.Candler@pobox.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org; batsman.geo@yahoo.com
Cc: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Friday, February 21, 2003 2:39 PM
Subject: Re: Style question: using ‘block_given?’

This is the class instance variable police. Freeze! Keine Bewegung!

:wink:

It’s a fair cop :slight_smile: I had a hard time getting my head round this one:

  • Class variables (@@data) are fine.

  • Instance variables in a module are fine: mix it into a class, and
    instances of that class get those instance variables too

  • But @data as a class instance variable? You can’t even refer to it,
    except from within a class method. (Unlike a class variable, @@data,
    which you can use within a normal instance method)

It looks like something which the language has by accident more than by
design :slight_smile:

Regards,

Brian.

Hi –

This is the class instance variable police. Freeze! Keine Bewegung!

:wink:

It’s a fair cop :slight_smile: I had a hard time getting my head round this one:

  • Class variables (@@data) are fine.

  • Instance variables in a module are fine: mix it into a class, and
    instances of that class get those instance variables too

  • But @data as a class instance variable? You can’t even refer to it,
    except from within a class method. (Unlike a class variable, @@data,
    which you can use within a normal instance method)

It’s probably most useful in an accessor. For example, if you want to
keep a running tally of how many instances of a class have been
created:

class C
class << self; protected; attr_accessor :instances; end
@instances = 0

def initialize
  self.class.instances += 1
end

end

p C.instances # 0
C.new
C.new
p C.instances # 2

It looks like something which the language has by accident more than by
design :slight_smile:

Only if consistent, predictable design happens by accident, which I
doubt :slight_smile: (See Gennady’s explanation.)

David

···

On Sat, 22 Feb 2003, Brian Candler wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

I think we need a RubyBlackMagic page on the Wiki :slight_smile:

I am probably being obtuse, but in order to decipher this I had to go the
long way round, starting with an analogy with with the normal usage of the
'class <<obj' pattern:

  class Foo
    # here, the current object (self) is 'Foo', of class 'Class'
  end

  a = Foo.new # 'a' is of class 'Foo'
  class <<a
    # the current object (self) is now a new Class which is a
    # singleton subclass of 'Foo'; and 'a' has been changed so that it
    # belongs to this new Class
    def bar; puts "hello"; end
  end
  puts a.bar #>> "hello" ('a' is of singleton class which includes 'bar')

  b = Foo.new
  puts b.bar #>> NameError ('b' is of class Foo which doesn't include 'bar')

So in the above, 'a' has been changed from an instance of 'Foo' to an
instance of an anonymous (singleton) class derived from 'Foo'.

Now, taking what you wrote:

  class C
    # the current object (self) is 'C' of class 'Class'
    class <<self
      # the current object (self) is now a new Class which is a
      # singleton subclass of 'Class'; and 'C' is changed so that it
      # belongs to this new class
      attr_accessor :instances
    end
  end

So, 'C' is no longer an instance of a regular 'Class', but an instance of an
anonymous subclass of 'Class' which has a counter.

Therefore, C.new generates an instance of an object whose class is this
'enhanced' class.

Consistent? Yes. Predictable? Perhaps, if you've seen it before :slight_smile:

<aside>
Question: does the code you wrote (subclassing Class) have the same effect
as adding class methods? i.e.

  class C
    def C.instances
      @instances
    end
    def C.instances=(val)
      @instances=val
    end
  end
</aside>

Anyway, taking the original example which was something like:

  class Tree
    @data = nil
    @kids = nil
    def initialize(data)
      @data = data
      @kids =
    end
  end

then I don't think it's immediately obvious at a glance that:

1. the first uses of '@data' and '@kids' are something completely different
   to the second uses

2. the things that you've created by the first assignments to '@data' and
   '@kids' are actually fairly well hidden; the only way you can get at
   them is via subclassing Class, or through class methods

3. even if you realise that the first uses of '@data' and '@kids' belong
   to the class and not to an instance of an object of that class, they
   are still not the same thing as '@@data' and '@@kids', which belong to
   the class but in a different way:

    class Tree
      @count = 0
      @@count = 50
      def Tree.inc
        @count += 1
      end
      def Tree.inc2
        @@count += 1
      end
    end
    puts Tree.inc #>> 1
    puts Tree.inc #>> 2
    puts Tree.inc2 #>> 51
    puts Tree.inc2 #>> 52
    puts Tree.instance_variables #>> @count
    puts Tree.class_variables #>> @@count

If you saw those things at a first glance, then I'd say you are a RubyWizard
:slight_smile:

Regards,

Brian.

···

On Sat, Feb 22, 2003 at 04:05:59PM +0900, dblack@candle.superlink.net wrote:

It's probably most useful in an accessor. For example, if you want to
keep a running tally of how many instances of a class have been
created:

  class C
    class << self; protected; attr_accessor :instances; end
    @instances = 0

    def initialize
      self.class.instances += 1
    end
  end

In article Pine.LNX.4.44.0302220205420.11431-100000@candle.superlink.net,

Hi –

This is the class instance variable police. Freeze! Keine Bewegung!

:wink:

It’s a fair cop :slight_smile: I had a hard time getting my head round this one:

  • Class variables (@@data) are fine.

  • Instance variables in a module are fine: mix it into a class, and
    instances of that class get those instance variables too

  • But @data as a class instance variable? You can’t even refer to it,
    except from within a class method. (Unlike a class variable, @@data,
    which you can use within a normal instance method)

It’s probably most useful in an accessor. For example, if you want to
keep a running tally of how many instances of a class have been
created:

class C
class << self; protected; attr_accessor :instances; end
@instances = 0

def initialize
self.class.instances += 1
end
end

p C.instances # 0
C.new
C.new
p C.instances # 2

Why wouldn’t I just use a class variable to do this (which is how I
usually do it when I need to keep track of how many instances have been
created):

class C
@@instances = 0
def initialize
@@instances += 1
end
def C.number_of_instances
@@instances
end
end

C.new
C.new
p C.number_of_instances #2

I suspect that the answer is that class variables are shared with
subclasses too, so that:

class D < C
def initialize
super
end
end

D.new
p D.number_of_instances #3
p C.number_of_instances #3

…instantiating D objects will also increment the count of C objects.
Sometimes this is desired behavior (when you want to keep track of the
number of instances of a particular class as well as instances of it’s
decendents) and sometimes not.

Is there any other advantage to your approach?

Phil

···

dblack@candle.superlink.net wrote:

On Sat, 22 Feb 2003, Brian Candler wrote:

Here's another one while we're on the subject of "consistent and
predictable" :slight_smile:

  class Tree
    @count = 0
    @@count = 50
    def Tree.inc
      @count += 1
    end
    def Tree.inc2
      @@count += 1
    end
  end

  def Tree.dec
    @count -= 1
  end
  def Tree.dec2
    @@count -= 1
  end

  puts Tree.inc #>> 1
  puts Tree.inc2 #>> 51
  puts Tree.dec #>> 0
  puts Tree.dec2 #>> uninitialized class variable @@count in Object (NameError)

(but in this case it's class variables, not class instance variables, which
appear to be behaving inconsistently)

Regards,

Brian.

Hi,

So, ‘C’ is no longer an instance of a regular ‘Class’, but an instance of an
anonymous subclass of ‘Class’ which has a counter.

All classes have their anonymous superclasses.

Equivalent.

···

At Sat, 22 Feb 2003 21:04:56 +0900, Brian Candler wrote:


Nobu Nakada

It’s perfectly obvious at a glance to me. True, I’ve faced difficulty
with such concepts in the past (at one point, I didn’t understand the
class << self business), but working through those difficulties is
necessary to become proficient in Ruby.

Not that I’m suggesting that difficult code be written for the sake of
it. Only that there’s no point shying away from complex-seeming
constructs which, thankfully, are part of the consistency of the
language.

Gavin

···

On Saturday, February 22, 2003, 11:04:56 PM, Brian wrote:

Anyway, taking the original example which was something like:

class Tree
@data = nil
@kids = nil
def initialize(data)
@data = data
@kids =
end
end

then I don’t think it’s immediately obvious at a glance that:

  1. the first uses of ‘@data’ and ‘@kids’ are something completely different
    to the second uses
  1. the things that you’ve created by the first assignments to ‘@data’ and
    @kids’ are actually fairly well hidden; the only way you can get at
    them is via subclassing Class, or through class methods

Hi –

It’s probably most useful in an accessor. For example, if you want to
keep a running tally of how many instances of a class have been
created:

class C
class << self; protected; attr_accessor :instances; end
@instances = 0

def initialize
  self.class.instances += 1
end

end

I think we need a RubyBlackMagic page on the Wiki :slight_smile:

Whoops – delete the ‘protected’. I was trying to see what that would
do, and forgot to delete it before cutting and pasting. (It was two
in the morning. I was also typing “fetchmail -a” on an irc
channel…)

I am probably being obtuse, but in order to decipher this I had to go the
long way round, starting with an analogy with with the normal usage of the
‘class <<obj’ pattern:

[snip … class << a …]

So in the above, ‘a’ has been changed from an instance of ‘Foo’ to an
instance of an anonymous (singleton) class derived from ‘Foo’.

Yes, though it’s a very particular kind of change. a.class will still
report Foo. The singleton class is anonymous and sort of
“transparent” – meaning, whatever information it fails to supply
(such as a name for itself) will come from the object’s historical
class. (That’s one of the differences between the singleton class
mechanism and subclassing.)

Now, taking what you wrote:

[snip … class << C …]

Therefore, C.new generates an instance of an object whose class is this
‘enhanced’ class.

Consistent? Yes. Predictable? Perhaps, if you’ve seen it before :slight_smile:

Ah, but you have seen it before – class << a in your example :slight_smile:
The consistency is what makes it predictable: what works for one
object works for another, even if one is a Foo and one is a Class.
(With the exception of Fixnums and Symbols, which you can’t do this
with.)

Anyway, taking the original example which was something like:

class Tree
@data = nil
@kids = nil
def initialize(data)
@data = data
@kids =
end
end

then I don’t think it’s immediately obvious at a glance that:

  1. the first uses of ‘@data’ and ‘@kids’ are something completely different
    to the second uses

That’s just practice – you get a sense of what ‘self’ is, and any
@x = y” type of assignment pertains to self’s instance variables.

  1. the things that you’ve created by the first assignments to ‘@data’ and
    @kids’ are actually fairly well hidden; the only way you can get at
    them is via subclassing Class, or through class methods

Except… C’s instance variables are visible only when self is C, and
subclassing Class results in a new instance of Class, which has its
own instance variables:

class C
@x = 1
end

class D
puts @x # nil
end

(Same as for instance variables across the board: they are only
visible when their owner is ‘self’.)

  1. even if you realise that the first uses of ‘@data’ and ‘@kids’ belong
    to the class and not to an instance of an object of that class, they
    are still not the same thing as ‘@@data’ and ‘@@kids’, which belong to
    the class but in a different way:

If you saw those things at a first glance, then I’d say you are a RubyWizard
:slight_smile:

I did see them at a glance, but I must respectfully decline the title,
since if we call me that, we’ll start running out of words to describe
the people higher up in the inheritance chain :slight_smile: I’m just a veteran
of some long sessions of communing with the “classes are instances
too” concept. See also
http://www.rubygarden.org/ruby?ClassMethodsTutorial if that’s
helpful.

David

···

On Sat, 22 Feb 2003, Brian Candler wrote:

On Sat, Feb 22, 2003 at 04:05:59PM +0900, dblack@candle.superlink.net wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi –

In article Pine.LNX.4.44.0302220205420.11431-100000@candle.superlink.net,

class C
class << self; protected; attr_accessor :instances; end
@instances = 0

def initialize
self.class.instances += 1
end
end

p C.instances # 0
C.new
C.new
p C.instances # 2

Why wouldn’t I just use a class variable to do this (which is how I
usually do it when I need to keep track of how many instances have been
created):

[snip]

I suspect that the answer is that class variables are shared with
subclasses too, so that:

[snip]

Is there any other advantage to your approach?

It does what I want; isn’t that enough? :slight_smile: That’s the thing –
tracking instances of a class and its descendants is different from
tracking instances of a class, so it’s not so much a choice between
two techniques for the task as a choice between two tasks.

David

···

On Sun, 23 Feb 2003, Phil Tomson wrote:

dblack@candle.superlink.net wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

You’re right on the distinction instances of this class (class
instance variables) vs. instances of this and all derived (class
variables).

I’d however rather do

batsman@tux-chan:/tmp$ expand -t 2 i.rb
module CountInstances
def new(*args, &p)
@instances ||= 0
@instances += 1
super(*args, &p)
end

def instances
@instances ||= 0
end
end

module CountHierarchyInstances
def new(*args, &p)
increment_count
super(*args, &p)
end

def increment_count
@instances ||= 0
@instances += 1
superclass.increment_count if superclass.kind_of? CountHierarchyInstances
end

def instances
@instances ||= 0
end

protected :increment_count
end

class A
extend CountInstances
def initialize
puts “Creating instance of #{self.class}”
end
end

class B < A

can have that functionality by subclassing A or using

#extend CountInstances
end

puts “Made #{A.instances} instances of A.”
puts “Made #{B.instances} instances of B.”
2.times { A.new; B.new }
1.times { B.new }
puts “Made #{A.instances} instances of A.”
puts “Made #{B.instances} instances of B.”

class A2
extend CountHierarchyInstances
def initialize
puts “Creating instance of #{self.class}”
end
end

class B2 < A2
end

puts “Made #{A2.instances} instances of A2.”
puts “Made #{B2.instances} instances of B2.”
2.times { A2.new; B2.new }
1.times { B2.new }
puts “Made #{A2.instances} instances of A2 or derived classes.”
puts “Made #{B2.instances} instances of B2 or derived classes.”
batsman@tux-chan:/tmp$ ruby i.rb
Made 0 instances of A.
Made 0 instances of B.
Creating instance of A
Creating instance of B
Creating instance of A
Creating instance of B
Creating instance of B
Made 2 instances of A.
Made 3 instances of B.
Made 0 instances of A2.
Made 0 instances of B2.
Creating instance of A2
Creating instance of B2
Creating instance of A2
Creating instance of B2
Creating instance of B2
Made 5 instances of A2 or derived classes.
Made 3 instances of B2 or derived classes.

…as this way you don’t have to keep using super all the time.
Moreover CountHierarchyInstances implements yet another valid semantic
for instance counting.

···

On Sun, Feb 23, 2003 at 08:46:22AM +0900, Phil Tomson wrote:

It’s probably most useful in an accessor. For example, if you want to
keep a running tally of how many instances of a class have been
created:

class C
class << self; protected; attr_accessor :instances; end
@instances = 0

def initialize
self.class.instances += 1
end
end

p C.instances # 0
C.new
C.new
p C.instances # 2

Why wouldn’t I just use a class variable to do this (which is how I
usually do it when I need to keep track of how many instances have been
created):

class C
@@instances = 0
def initialize
@@instances += 1
end
def C.number_of_instances
@@instances
end
end

C.new
C.new
p C.number_of_instances #2


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

There are 3 kinds of people: those who can count & those who can’t.
– Unknown source

It is. Thank you.

Regards,

Brian.

···

On Sun, Feb 23, 2003 at 12:46:06AM +0900, dblack@candle.superlink.net wrote:

I'm just a veteran
of some long sessions of communing with the "classes are instances
too" concept. See also
<http://www.rubygarden.org/ruby?ClassMethodsTutorial&gt; if that's
helpful.

The class whose variable will be used is selected at compile time.
IMHO this is evil as it is a closure-like mechanism — on a class method
level — not available when using locals.

It is at least evil enough to deserve a warning :slight_smile:

batsman@tux-chan:/tmp$ expand -t 2 l.rb
class Tree
@@count = “Tree’s @@count
def Tree.dec
p @@count.id, @@count
end
end

@@count = “Top level’s”
class << self
@@count = “Top level’s (2)”

it’s the same class variable.

end

def Tree.dec2
p @@count.id, @@count

refers to the class variable of the top-level object’s class

not that of Tree

end

class << Tree
def dec3
p @@count.id, @@count
end
end

class Tree
class << self
def dec4
p @@count.id, @@count
end
end
end

class SubTree < Tree
def SubTree.inc
p @@count.id, @@count
end
end

p self.class
Tree.dec
Tree.dec2
Tree.dec3
Tree.dec4
SubTree.inc
batsman@tux-chan:/tmp$ ruby l.rb
l.rb:10: warning: class variable access from toplevel singleton method
Object
538045926
“Tree’s @@count
538045876
“Top level’s (2)”
l.rb:22: warning: class variable access from toplevel singleton method
l.rb:22: warning: class variable access from toplevel singleton method
538045876
“Top level’s (2)”
538045926
“Tree’s @@count
538045926
“Tree’s @@count

···

On Sat, Feb 22, 2003 at 09:38:17PM +0900, Brian Candler wrote:

Here’s another one while we’re on the subject of “consistent and
predictable” :slight_smile:

class Tree
@count = 0
@@count = 50
def Tree.inc
@count += 1
end
def Tree.inc2
@@count += 1
end
end

def Tree.dec
@count -= 1
end
def Tree.dec2
@@count -= 1
end

puts Tree.inc #>> 1
puts Tree.inc2 #>> 51
puts Tree.dec #>> 0
puts Tree.dec2 #>> uninitialized class variable @@count in Object (NameError)

(but in this case it’s class variables, not class instance variables, which
appear to be behaving inconsistently)


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Tut mir Leid, Jost, aber Du bist ein unertraeglicher Troll.
Was soll das? Du beleidigst die Trolle!
– de.comp.os.unix.linux.misc

Gavin,

Your message raises the obvious question for me – given that I don’t
understand the ‘class << self’ business – what is the meaning and
usage of ‘class << self’? Please help me truly understand. Thanks.

Mark

···

On Saturday, February 22, 2003, at 09:31 AM, Gavin Sinclair wrote:

[snip]
It’s perfectly obvious at a glance to me. True, I’ve faced difficulty
with such concepts in the past (at one point, I didn’t understand the
class << self business), but working through those difficulties is
necessary to become proficient in Ruby.

Not that I’m suggesting that difficult code be written for the sake of
it. Only that there’s no point shying away from complex-seeming
constructs which, thankfully, are part of the consistency of the
language.
[snip]

[snip]
It’s perfectly obvious at a glance to me. True, I’ve faced difficulty
with such concepts in the past (at one point, I didn’t understand the
class << self business), but working through those difficulties is
necessary to become proficient in Ruby.

Not that I’m suggesting that difficult code be written for the sake of
it. Only that there’s no point shying away from complex-seeming
constructs which, thankfully, are part of the consistency of the
language.
[snip]

Gavin,

Your message raises the obvious question for me – given that I don’t
understand the ‘class << self’ business – what is the meaning and
usage of ‘class << self’? Please help me truly understand. Thanks.

(skip as much as required :slight_smile:

class << someobj
end

allows you to add singleton methods to one object (that is, add methods
to its singleton class).

a = “aaa”
=> “aaa”
class << a
def foo
puts “ho” * 3
end
end
=> nil
a.foo
hohoho
=> nil

Classes are objects too

class A; end
=> nil
A.id
=> 538275918

and as such you can add singleton methods to them:

class << A
def bar
puts “bar” * 4
end
end
=> nil
A.bar
barbarbarbar
=> nil

Now, inside class A; …; end, self refers to the class object (that of
class Class :slight_smile:

A.id
=> 538275918
class A; self.id; end
=> 538275918
class A; self.class; end
=> Class

Now we use both ‘class << someobj’ and the fact that, inside the
‘class SomeClass; … ; end’ construct, self refers to the class. We
thus add singleton methods, that is, class methods

class A
class << self
def baz
puts "baz " * 4
end
end
end
=> nil
A.baz
baz baz baz baz
=> nil

So that idiom corresponds to doing

def A.baz2
puts "baz " * 4
end
=> nil
A.baz2
baz baz baz baz
=> nil

One cool thing about singleton method definitions is that they can be
nested inside other method defs:

def foo(a)
def a.babar
puts “I am #{self.id}”
end
end
=> nil
b = “fdgdfgf”
=> “fdgdfgf”
foo(b)
=> nil
b.babar
I am 538152868
=> nil

That is equivalent to

def foo(a)
class << a
def babar
puts “My id is #{self.id}”
end
end
end
=> nil
b = “abcd”
=> “abcd”
foo(b)
=> nil
b.babar
My id is 538276118
=> nil

One reason to prefer ‘class << obj’ over ‘def obj.’ is that it is
possible to capture the singleton class that way:

class << b; self; end
=> String # reported as ‘String’ but it is actually the singleton class of b!

Imagine for instance that you don’t want the singleton class (and therefore
the singleton methods) of an object to be modified; you’d do

class << someobj; self.freeze; end

···

On Sun, Feb 23, 2003 at 04:24:37AM +0900, Mark Wilson wrote:

On Saturday, February 22, 2003, at 09:31 AM, Gavin Sinclair wrote:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

  • long f_ffree; /* free file nodes in fs */
  • long f_ffree; /* freie Dateiknoten im Dateisystem */
    – Seen in a translation

You’ve seen the other replies, now look at ClassMethodsTutorial on the
wiki and remember it’s there next time someone asks you about all this
stuff!

Cheers,
Gavin

···

On Sunday, February 23, 2003, 6:24:37 AM, Mark wrote:

Gavin,

Your message raises the obvious question for me – given that I don’t
understand the ‘class << self’ business – what is the meaning and
usage of ‘class << self’? Please help me truly understand. Thanks.