why is my singleton method called before the class is initialize?

B

bachase

Consider:

class BigGuy
def initialize
@favorites = ["a","b","c"]
end

class << self
def display_favs
class_eval "p @favorites"
end
end
end

class LittleGuy < BigGuy
display_favs
end

Why does this display "nil"? I expected the initialize of BigGuy to
occur prior to invoking display_favs. Any other construction I should
be using to get my desire behavior of the constructor of the base class
getting called prior to singleton methods called from the child class?
 
M

matt neuburg

Consider:

class BigGuy
def initialize
@favorites = ["a","b","c"]
end

class << self
def display_favs
class_eval "p @favorites"
end
end
end

class LittleGuy < BigGuy
display_favs
end

Why does this display "nil"? I expected the initialize of BigGuy to
occur prior to invoking display_favs. Any other construction I should
be using to get my desire behavior of the constructor of the base class
getting called prior to singleton methods called from the child class?

"Initialize" is called when the class is instantiated (i.e. with new).
You are never instantiating this class, so "initialize" is never called.
m.
 
R

Rick DeNatale

Consider:

class BigGuy
def initialize
@favorites = ["a","b","c"]
end

class << self
def display_favs
class_eval "p @favorites"
end
end
end

class LittleGuy < BigGuy
display_favs
end

Why does this display "nil"? I expected the initialize of BigGuy to
occur prior to invoking display_favs. Any other construction I should
be using to get my desire behavior of the constructor of the base class
getting called prior to singleton methods called from the child class?

"Initialize" is called when the class is instantiated (i.e. with new).
You are never instantiating this class, so "initialize" is never called.

True, but kind of beside the point. The initialize method if and when
it is called will set the instance variable @favorites in a new
INSTANCE of BigGuy.

class BigGuy
...
class << self
def display_favs
class_eval "p @favorites"
end
end
end

This makes display_favs a class method of BigGuy.
In the method display_favs self is the class object BigGuy.

so
class_eval "p @favorites"
is the same as
BigGuy.class_eval "p @favorites"

which is printing a class instance variable of BigGuy which doesn't exist.

And...

class LittleGuy < BigGuy
display_favs
end

inside this class definition, self is LittleGuy so

display_favs
is equivalent to:
LittleGuy.display_favs

which executes
BigGuy::display_favs

by inheritance

which prints the uninitialized class instance variable @favorites.

Note also that the class instance variable @favorite in BigGuy is
different from the clas instance variable @favorite in LittleGuy,
although neither one is initialized.
 
M

matt neuburg

Rick DeNatale said:
Consider:

class BigGuy
def initialize
@favorites = ["a","b","c"]
end

class << self
def display_favs
class_eval "p @favorites"
end
end
end

class LittleGuy < BigGuy
display_favs
end

Why does this display "nil"? I expected the initialize of BigGuy to
occur prior to invoking display_favs. Any other construction I should
be using to get my desire behavior of the constructor of the base class
getting called prior to singleton methods called from the child class?

"Initialize" is called when the class is instantiated (i.e. with new).
You are never instantiating this class, so "initialize" is never called.

True, but kind of beside the point.

Perhaps it's a matter of pedagogy. What *is* "the point"? That depends
on where one thinks the OP has ultimately gone wrong. The OP might have
any of several misconceptions (it is hard to be certain); the OP might
not be aware:

(1) that initialize is called at instantiation time.

(2) that a class and an instance of that class are different things.

(3) that the singleton method is a class method.

(4) that the @favorites referred to in the class method is not the
@favorites referred to in "initialize".

Each of us is trying to teach, so each of us, like a good teacher, made
a guess about where the heart of the OP's misunderstanding might lie. I
guessed (1), with a little bit of (2) thrown in. You are leaning more
toward (3) and (4). Your guess is reasonable, but my guess is not
unreasonable, especially since the OP explicitly said: "I expected the
initialize ... to occur". I spoke to that issue, showing why that
expectation was wrong. So what I said is hardly "beside the point".

m.
 
B

bachase

I'll say thanks to both of you. I think I was confused on all
accounts, but the biggest issue is probably that I thought the
@favorites was the same for both classes. I guess I will need to
restructure things then. Basically, I want the base class to provide
some default settings that a child class could override using a class
method. Apparently, I am unclear on the way to do so.

matt said:
Rick DeNatale said:
Consider:

class BigGuy
def initialize
@favorites = ["a","b","c"]
end

class << self
def display_favs
class_eval "p @favorites"
end
end
end

class LittleGuy < BigGuy
display_favs
end

Why does this display "nil"? I expected the initialize of BigGuy to
occur prior to invoking display_favs. Any other construction I should
be using to get my desire behavior of the constructor of the base class
getting called prior to singleton methods called from the child class?

"Initialize" is called when the class is instantiated (i.e. with new).
You are never instantiating this class, so "initialize" is never called.

True, but kind of beside the point.

Perhaps it's a matter of pedagogy. What *is* "the point"? That depends
on where one thinks the OP has ultimately gone wrong. The OP might have
any of several misconceptions (it is hard to be certain); the OP might
not be aware:

(1) that initialize is called at instantiation time.

(2) that a class and an instance of that class are different things.

(3) that the singleton method is a class method.

(4) that the @favorites referred to in the class method is not the
@favorites referred to in "initialize".

Each of us is trying to teach, so each of us, like a good teacher, made
a guess about where the heart of the OP's misunderstanding might lie. I
guessed (1), with a little bit of (2) thrown in. You are leaning more
toward (3) and (4). Your guess is reasonable, but my guess is not
unreasonable, especially since the OP explicitly said: "I expected the
initialize ... to occur". I spoke to that issue, showing why that
expectation was wrong. So what I said is hardly "beside the point".

m.
The initialize method if and when
it is called will set the instance variable @favorites in a new
INSTANCE of BigGuy.

class BigGuy
...
class << self
def display_favs
class_eval "p @favorites"
end
end
end

This makes display_favs a class method of BigGuy.
In the method display_favs self is the class object BigGuy.

so
class_eval "p @favorites"
is the same as
BigGuy.class_eval "p @favorites"

which is printing a class instance variable of BigGuy which doesn't exist.

And...

class LittleGuy < BigGuy
display_favs
end

inside this class definition, self is LittleGuy so

display_favs
is equivalent to:
LittleGuy.display_favs

which executes
BigGuy::display_favs

by inheritance

which prints the uninitialized class instance variable @favorites.

Note also that the class instance variable @favorite in BigGuy is
different from the clas instance variable @favorite in LittleGuy,
although neither one is initialized.


--
matt neuburg, phd = (e-mail address removed), http://www.tidbits.com/matt/
Tiger - http://www.takecontrolbooks.com/tiger-customizing.html
AppleScript - http://www.amazon.com/gp/product/0596102119
Read TidBITS! It's free and smart. http://www.tidbits.com
 
A

ara.t.howard

I'll say thanks to both of you. I think I was confused on all
accounts, but the biggest issue is probably that I thought the
@favorites was the same for both classes. I guess I will need to
restructure things then. Basically, I want the base class to provide
some default settings that a child class could override using a class
method. Apparently, I am unclear on the way to do so.

it's astonishingly hard to do in a generic way. take my word for it, the
easiest way is to do

harp:~ > cat a.rb
require 'rubygems'
require 'attributes'

class C
class << self
attribute 'a' => 42
end
end

class K < C
end

p C.a
p K.a

class K
a 'forty-two'
end

p C.a
p K.a


harp:~ > ruby a.rb
42
42
42
"forty-two"

regards.

-a
 
J

Jean Helou

If you want to do it at the class level instead of the instance level,
it looks like what is done quite a lot in rails

for example in active record :

class Toto<<ActiveRecord::Base
end

would use totos as table name by default (define by AR) but you can
chage it to something else like this :

class Toto<<ActiveRecord::Base
set_table_name "mice"
end

now it will use mice instead of toto

if this is what you are trying to do, have a look at rails
implementation, which relies on rails define_attr_method :
http://railsmanual.org/class/ActiveRecord::Base/define_attr_method

hope this helps

I'll say thanks to both of you. I think I was confused on all
accounts, but the biggest issue is probably that I thought the
@favorites was the same for both classes. I guess I will need to
restructure things then. Basically, I want the base class to provide
some default settings that a child class could override using a class
method. Apparently, I am unclear on the way to do so.

matt said:
Rick DeNatale said:
Consider:

class BigGuy
def initialize
@favorites = ["a","b","c"]
end

class << self
def display_favs
class_eval "p @favorites"
end
end
end

class LittleGuy < BigGuy
display_favs
end

Why does this display "nil"? I expected the initialize of BigGuy to
occur prior to invoking display_favs. Any other construction I should
be using to get my desire behavior of the constructor of the base class
getting called prior to singleton methods called from the child class?

"Initialize" is called when the class is instantiated (i.e. with new).
You are never instantiating this class, so "initialize" is never called.

True, but kind of beside the point.

Perhaps it's a matter of pedagogy. What *is* "the point"? That depends
on where one thinks the OP has ultimately gone wrong. The OP might have
any of several misconceptions (it is hard to be certain); the OP might
not be aware:

(1) that initialize is called at instantiation time.

(2) that a class and an instance of that class are different things.

(3) that the singleton method is a class method.

(4) that the @favorites referred to in the class method is not the
@favorites referred to in "initialize".

Each of us is trying to teach, so each of us, like a good teacher, made
a guess about where the heart of the OP's misunderstanding might lie. I
guessed (1), with a little bit of (2) thrown in. You are leaning more
toward (3) and (4). Your guess is reasonable, but my guess is not
unreasonable, especially since the OP explicitly said: "I expected the
initialize ... to occur". I spoke to that issue, showing why that
expectation was wrong. So what I said is hardly "beside the point".

m.
The initialize method if and when
it is called will set the instance variable @favorites in a new
INSTANCE of BigGuy.

class BigGuy
...
class << self
def display_favs
class_eval "p @favorites"
end
end
end

This makes display_favs a class method of BigGuy.
In the method display_favs self is the class object BigGuy.

so
class_eval "p @favorites"
is the same as
BigGuy.class_eval "p @favorites"

which is printing a class instance variable of BigGuy which doesn't exist.

And...

class LittleGuy < BigGuy
display_favs
end

inside this class definition, self is LittleGuy so

display_favs
is equivalent to:
LittleGuy.display_favs

which executes
BigGuy::display_favs

by inheritance

which prints the uninitialized class instance variable @favorites.

Note also that the class instance variable @favorite in BigGuy is
different from the clas instance variable @favorite in LittleGuy,
although neither one is initialized.


--
matt neuburg, phd = (e-mail address removed), http://www.tidbits.com/matt/
Tiger - http://www.takecontrolbooks.com/tiger-customizing.html
AppleScript - http://www.amazon.com/gp/product/0596102119
Read TidBITS! It's free and smart. http://www.tidbits.com
 
M

matt neuburg

matt neuburg said:
class BigGuy
def setup
@favorites = "bluto"
end
def initialize
setup
p @favorites
end
class MiddleGuy < BigGuy
end
def BigGuy.make_subclass(what)
MiddleGuy.class_eval %{
def setup
@favorites = "#{what}"
end
}
return MiddleGuy
end
end

class LittleGuy < BigGuy.make_subclass('popeye')
end

Okay, scratch that. It's fatally flawed. Oh, well. m.
 
M

matt neuburg

matt neuburg said:
Okay, scratch that. It's fatally flawed. Oh, well. m.

Aha! This is better:

###

class BigGuy
def setup
@favorites = "bluto"
end
def initialize
setup
p @favorites
end
class MiddleGuy < BigGuy
end
def self.make_subclass(what)
p = Proc.new {@favorites = what}
MiddleGuy.send( :define_method, :setup, p )
return MiddleGuy.clone
end
end

class LittleGuy < BigGuy.make_subclass('popeye')
end
class DevilishGuy < BigGuy.make_subclass(666)
end

BigGuy.new #=> "bluto"
LittleGuy.new #=> "popeye"
BigGuy.new #=> "bluto"
DevilishGuy.new #=> 666
LittleGuy.new #=> "popeye"

###

The Proc handles the problem with eval that I was having before, so any
kind of value can now be passed to make_subclass. The other problem I
was having is that we if called make_subclass twice with different
values, only one of those values was being used; hence the "clone" call.

Perhaps this will give the OP something to build on... Anyway it was fun
to think about.

m.
 
J

Jacob Fugal

class BigGuy
def setup
@favorites = "bluto"
end
def initialize
setup
p @favorites
end
class MiddleGuy < BigGuy
end
def self.make_subclass(what)
p = Proc.new {@favorites = what}
MiddleGuy.send( :define_method, :setup, p )
return MiddleGuy.clone
end
end

You can do away with the explicit "MiddleGuy" class and the clone
call, by just creating an anonymous class on each invocation:

class BigGuy
def setup
@favorites = "bluto"
end

def initialize
setup
p @favorites
end

def self.with_favorites(favorites)
Class.new(self) do
define_method:)setup) do
@favorites = favorites
end
end
end
end

And while we're at it, if the only purpose of the on-the-fly class was
for the subclass to inherit from, why not make the subclass *be* the
on-the-fly class:

LittleGuy = BigGuy.with_favorites('popeye')
DevilishGuy = BigGuy.with_favorites(666)

Then the following code produces the same output as yours above:

BigGuy.new #=> "bluto"
LittleGuy.new #=> "popeye"
BigGuy.new #=> "bluto"
DevilishGuy.new #=> 666
LittleGuy.new #=> "popeye"

Jacob Fugal
 
M

matt neuburg

Jacob Fugal said:
You can do away with the explicit "MiddleGuy" class and the clone
call, by just creating an anonymous class on each invocation:

class BigGuy
def setup
@favorites = "bluto"
end

def initialize
setup
p @favorites
end

def self.with_favorites(favorites)
Class.new(self) do
define_method:)setup) do
@favorites = favorites
end
end
end
end

And while we're at it, if the only purpose of the on-the-fly class was
for the subclass to inherit from, why not make the subclass *be* the
on-the-fly class:

LittleGuy = BigGuy.with_favorites('popeye')
DevilishGuy = BigGuy.with_favorites(666)

Then the following code produces the same output as yours above:

BigGuy.new #=> "bluto"
LittleGuy.new #=> "popeye"
BigGuy.new #=> "bluto"
DevilishGuy.new #=> 666
LittleGuy.new #=> "popeye"

Yeah! I could NOT for the life of me figure out how to make that
anonymous class, and the direct assignment just didn't occur to me.
Thanks - m.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top