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

On 24.09.2008 07:55, Ittay D. wrote:

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

(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.

Brian C. 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 B.'s post
Ola Bini: Programming Language Synchronicity: Nooks and Crannies of Ruby. 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

arg2 = [4,5,6]
You can also use it for multiple assignments:

info.
def doit2(x,y,&blk)
arr.each(&callback)
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 D. [email protected]
Tikal http://www.tikalk.com
Tikal Project http://tikal.sourceforge.net

2008/9/24 Ittay D. [email protected]:

Thanks for the response, I was looking more to something along the lines of
Ola B.'s post
Ola Bini: Programming Language Synchronicity: Nooks and Crannies of Ruby. 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

Hi –

On Wed, 24 Sep 2008, Ittay D. wrote:

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

Ittay D. wrote:

Thanks for the response, I was looking more to something along the lines
of Ola B.'s post
Ola Bini: Programming Language Synchronicity: Nooks and Crannies of Ruby.

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.