Understanding inheritance and class singleton methods

Hi,

I'll start with what I understand:
class Foo
   class << self
      def hi
         puts 'HI'
      end
   end
end

Creates an instance of a singleton class that has the method #hi. So Foo.hi calls the method defined in the class of Foo -> the singleton class (which inherits from Class)

My question:
class Bar < Foo
end

Bar.hi --> 'HI'

It looks like two things are happening: 1. Bar points to Foo, so instances of Bar lookup methods in Foo also. 2. The instance Bar has a class that inherits from Foo's instance class.

Is this correct? Is there somewhere where I can find the exact flow of '<' (and '<<')? (or for that matter, specifications how 'splat' behaves and the '&' operator before blocks)

Thank you,
Ittay

···

--
--
Ittay Dror <ittay.dror@gmail.com>

Hi,

I'll start with what I understand:
class Foo
   class << self
      def hi
         puts 'HI'
      end
   end
end

Creates an instance of a singleton class that has the method #hi. So Foo.hi calls the method defined in the class of Foo -> the singleton class (which inherits from Class)

My question:
class Bar < Foo
end

Bar.hi --> 'HI'

It looks like two things are happening: 1. Bar points to Foo, so instances of Bar lookup methods in Foo also. 2. The instance Bar has a class that inherits from Foo's instance class.

Is this correct?

Basically yes. Although singleton classes are a bit tricky - they are partly hidden (for example, you do not see them via Module#ancestors).

Is there somewhere where I can find the exact flow of '<' (and '<<')?

AFAIK you cannot really "see" this:

irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> class Bar < Foo; end
=> nil
irb(main):003:0> $fc = class <<Foo; self end
=> #<Class:Foo>
irb(main):004:0> $bc = class <<Bar; self end
=> #<Class:Bar>
irb(main):005:0> $bc < $fc
=> nil
irb(main):006:0> $bc > $fc
=> false
irb(main):007:0> $bc.ancestors
=> [Class, Module, Object, PP::ObjectMixin, Kernel]
irb(main):008:0> $fc.ancestors
=> [Class, Module, Object, PP::ObjectMixin, Kernel]
irb(main):009:0> Foo < $fc
=> nil
irb(main):011:0> $fc.superclass
=> #<Class:Class>
irb(main):012:0> $bc.superclass
=> #<Class:Class>

I keep remembering that instance methods of a singleton class are inherited by singleton classes of subclasses. This has served me well in the past. :slight_smile:

Cheers

  robert

···

On 24.09.2008 07:55, Ittay Dror wrote:

(or for that matter, specifications how 'splat' behaves
and the '&' operator before blocks)

Splat turns an array into an argument list, or vice versa.

  def test1(*args)
    p args
  end
  test1(1,2,3) # prints the array [1, 2, 3]

  def test2(a, b, c)
    p a, b, c
  end
  arg2 = [4,5,6]
  test2(*arg2) # prints 4 then 5 then 6

You can use splat to "mop up" remaining arguments:

  def test3(a, b, *rest)
    p a, b, rest
  end
  test3(7, 8) # prints 7 then 8 then
  test3(7, 8, 9) # prints 7 then 8 then [9]

You can also use it for multiple assignments:

  a, b = *[10, 11]

and you can use it in blocks: foo { |x,*y| ... }

Where it gets confusing is special "autosplat" magic which happens for
multiple assignments and blocks where one side is a single array.

  a, b = [10, 11]
  p a, b # [10, 11]

  foo = 12, 13, 14
  p foo # [12, 13, 14]

  arr = [ ["foo",1], ["bar",2], ["baz",3] ]
  arr.each { |x,y| p x, y }

  p arr.inject(0) { |accum,(k,v)| accum + k.length + v }

Fortunately, autosplat doesn't happen for method calls, AFAIK. See
http://innig.net/software/ruby/closures-in-ruby.rb (section 4) for more
info.

As for the & operator, this is pretty simple. It's just a way of turning
the "hidden" block argument into a concrete argument.

The following two are equivalent:

  def doit1(x,y)
    yield x+y
  end

  def doit2(x,y,&blk)
    blk.call(x+y)
  end

Conversely, if you have an existing proc/lambda type of object, you can
pass it instead of an inline block:

  arr = ["foo", "bar"]
  arr.each { |elem| puts "hello #{elem}" }

  callback = lambda { |elem| puts "hello #{elem}" }
  arr.each(&callback)

And hence the blk itself can be passed around as an object. So:

  def doit3(arr)
    arr.each { |elem| yield elem }
  end

becomes simply

  def doit4(arr,&blk)
    arr.each(&blk)
  end

Personally, I found blocks and yield much easier to understand once I
saw they were just passing a function as an extra argument, and calling
that argument.

···

--
Posted via http://www.ruby-forum.com/\.

Hi --

Hi,

I'll start with what I understand:
class Foo
class << self
    def hi
       puts 'HI'
    end
end
end

Creates an instance of a singleton class that has the method #hi. So Foo.hi calls the method defined in the class of Foo -> the singleton class (which inherits from Class)

My question:
class Bar < Foo
end

Bar.hi --> 'HI'

It looks like two things are happening: 1. Bar points to Foo, so instances of Bar lookup methods in Foo also. 2. The instance Bar has a class that inherits from Foo's instance class.

The singleton class of Foo is the superclass of the singleton class of
Bar. Actually, this is broken in 1.8.6, but if you look at 1.8.2
(that's the earlier one I happen to have around) or 1.9, it works:

class Object; def singleton_class; class << self; self; end; end; end

=> nil

class C; end

=> nil

class D < C; end

=> nil

D.singleton_class.superclass == C.singleton_class

=> true

That's why D can reach C's singleton (i.e., class) methods: D's lookup
path includes its own singleton class, and that class's superclass.
It's also why the word "singleton" is less of a perfect fit when
classes are involved, since C's singleton methods are actually
callable by another object. So sometimes a class's singleton class is
referred to as a metaclass (which isn't a perfect fit either, but it
marks the distinction).

David

···

On Wed, 24 Sep 2008, Ittay Dror wrote:

--
Rails training from David A. Black and Ruby Power and Light:
   Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
   Advancing with Rails January 19-22 Fort Lauderdale, FL *
   * Co-taught with Patrick Ewing!
See http://www.rubypal.com for details and updates!

Brian Candler wrote:

(or for that matter, specifications how 'splat' behaves
and the '&' operator before blocks)
    

Thanks for the response, I was looking more to something along the lines of Ola Bini's post http://ola-bini.blogspot.com/2006/11/nooks-and-crannies-of-ruby.html\. He describes there that the splat operator works by first checking if the object has a to_a which allows for some cool tricks. What I want to know is where he got this information from? (digging through the C code?)

Ittay

···

Splat turns an array into an argument list, or vice versa.

  def test1(*args)
    p args
  end
  test1(1,2,3) # prints the array [1, 2, 3]

  def test2(a, b, c)
    p a, b, c
  end
  arg2 = [4,5,6]
  test2(*arg2) # prints 4 then 5 then 6

You can use splat to "mop up" remaining arguments:

  def test3(a, b, *rest)
    p a, b, rest
  end
  test3(7, 8) # prints 7 then 8 then
  test3(7, 8, 9) # prints 7 then 8 then [9]

You can also use it for multiple assignments:

  a, b = *[10, 11]

and you can use it in blocks: foo { |x,*y| ... }

Where it gets confusing is special "autosplat" magic which happens for multiple assignments and blocks where one side is a single array.

  a, b = [10, 11]
  p a, b # [10, 11]

  foo = 12, 13, 14
  p foo # [12, 13, 14]

  arr = [ ["foo",1], ["bar",2], ["baz",3] ]
  arr.each { |x,y| p x, y }

  p arr.inject(0) { |accum,(k,v)| accum + k.length + v }

Fortunately, autosplat doesn't happen for method calls, AFAIK. See http://innig.net/software/ruby/closures-in-ruby.rb (section 4) for more info.

As for the & operator, this is pretty simple. It's just a way of turning the "hidden" block argument into a concrete argument.

The following two are equivalent:

  def doit1(x,y)
    yield x+y
  end

  def doit2(x,y,&blk)
    blk.call(x+y)
  end

Conversely, if you have an existing proc/lambda type of object, you can pass it instead of an inline block:

  arr = ["foo", "bar"]
  arr.each { |elem| puts "hello #{elem}" }

  callback = lambda { |elem| puts "hello #{elem}" }
  arr.each(&callback)

And hence the blk itself can be passed around as an object. So:

  def doit3(arr)
    arr.each { |elem| yield elem }
  end

becomes simply

  def doit4(arr,&blk)
    arr.each(&blk)
  end

Personally, I found blocks and yield much easier to understand once I saw they were just passing a function as an extra argument, and calling that argument.
  
--
Ittay Dror <ittayd@tikalk.com>
Tikal <http://www.tikalk.com>
Tikal Project <http://tikal.sourceforge.net>

--
--
Ittay Dror <ittay.dror@gmail.com>

Ittay Dror wrote:

Thanks for the response, I was looking more to something along the lines
of Ola Bini's post
http://ola-bini.blogspot.com/2006/11/nooks-and-crannies-of-ruby.html\.

Then I refer you to that post :slight_smile:

What I want to know
is where he got this information from? (digging through the C code?)

Only he could answer that. Apart from looking at the source, maybe it
was experimentation in irb, or collating previous mailing list postings,
combining to form accumulated experience and wisdom.

I'm afraid there is no formal spec for the language that I'm aware of.

···

--
Posted via http://www.ruby-forum.com/\.

Thanks for the response, I was looking more to something along the lines of
Ola Bini's post
http://ola-bini.blogspot.com/2006/11/nooks-and-crannies-of-ruby.html\. He
describes there that the splat operator works by first checking if the
object has a to_a which allows for some cool tricks.

I believe this is not completely correct (see below).

What I want to know is
where he got this information from? (digging through the C code?)

You can test this out yourself.

11:39:01 ~$ ./sp.rb
./sp.rb:7 [1, 2, 3]
./sp.rb:8 [[1, 2, 3]]
./sp.rb:9 [1..3]
./sp.rb:10 [1, 2, 3]
["to_a"]
./sp.rb:15 [#<Object:0x1002e274>]
./sp.rb:16 [#<Object:0x1002e274>]
./sp.rb:23 [#<Object:0x1002e274>]
to_a
./sp.rb:24 ["to_a"]
./sp.rb:31 [#<Object:0x1002e274>]
to_ary
./sp.rb:32 ["to_ary"]
11:39:03 ~$ cat sp.rb
#!/bin/env ruby

def t *a
  printf "%s %p\n", caller.first, a
end

t 1,2,3
t [1,2,3]
t (1..3)
t *(1..3)

o = Object.new
p o.methods.grep(/to_a/)

t o
t *o

def o.to_a
  puts "to_a"
  ["to_a"]
end

t o
t *o

def o.to_ary
  puts "to_ary"
  ["to_ary"]
end

t o
t *o
11:39:10 ~$

Kind regards

robert

···

2008/9/24 Ittay Dror <ittay.dror@gmail.com>:

--
use.inject do |as, often| as.you_can - without end