[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

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

bachase@gmail.com

10/27/2006 1:37:00 AM

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?

11 Answers

matt

10/27/2006 1:50:00 AM

0

bachase@gmail.com <bachase@gmail.com> wrote:

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


--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

Rick DeNatale

10/27/2006 2:14:00 AM

0

On 10/26/06, matt neuburg <matt@tidbits.com> wrote:
> bachase@gmail.com <bachase@gmail.com> wrote:
>
> > 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.


--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

matt

10/27/2006 3:09:00 AM

0

Rick DeNatale <rick.denatale@gmail.com> wrote:

> On 10/26/06, matt neuburg <matt@tidbits.com> wrote:
> > bachase@gmail.com <bachase@gmail.com> wrote:
> >
> > > 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 = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

bachase@gmail.com

10/27/2006 3:22:00 AM

0

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 neuburg wrote:
> Rick DeNatale <rick.denatale@gmail.com> wrote:
>
> > On 10/26/06, matt neuburg <matt@tidbits.com> wrote:
> > > bachase@gmail.com <bachase@gmail.com> wrote:
> > >
> > > > 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 = matt@tidbits.com, http://www.tidbits...
> Tiger - http://www.takecontrolbooks.com/tiger-custom...
> AppleScript - http://www.amazon.com/gp/product/...
> Read TidBITS! It's free and smart. http://www.t...

Ara.T.Howard

10/27/2006 3:55:00 AM

0

matt

10/27/2006 4:55:00 AM

0

bachase@gmail.com <bachase@gmail.com> wrote:

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

I guess I'm wondering: does it absolutely have to be a class method?
Could it be an ordinary instance method? In this approach, as you
subclass you get to define an instance method, "setup", that you know
will be called by the constructor:

###

class BigGuy
def setup
@favorites = "bluto"
end
def initialize
setup
p @favorites
end
end

class LittleGuy < BigGuy
def setup
@favorites = "popeye"
end
end

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

###

If you really do want it to be class-based, perhaps a class method might
generate a subclass, set up the way you want it, from which you derive
further subclasses. I'm not very adept at this sort of thing, but my
first go would be something like this:

###

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

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

###

I like the ultimate syntax used to generate LIttleGuy, but I'm not
entirely happy because it assumes that the parameter is a string. But I
got all caught up the "eval" situation and couldn't think straight any
more after a while... Maybe it was a silly idea. m.

--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

Jean Helou

10/27/2006 9:10:00 AM

0

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

hope this helps

On 10/27/06, bachase@gmail.com <bachase@gmail.com> wrote:
> 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 neuburg wrote:
> > Rick DeNatale <rick.denatale@gmail.com> wrote:
> >
> > > On 10/26/06, matt neuburg <matt@tidbits.com> wrote:
> > > > bachase@gmail.com <bachase@gmail.com> wrote:
> > > >
> > > > > 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 = matt@tidbits.com, http://www.tidbits...
> > Tiger - http://www.takecontrolbooks.com/tiger-custom...
> > AppleScript - http://www.amazon.com/gp/product/...
> > Read TidBITS! It's free and smart. http://www.t...
>
>
>

matt

10/27/2006 2:10:00 PM

0

matt neuburg <matt@tidbits.com> wrote:

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

--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

matt

10/27/2006 2:51:00 PM

0

matt neuburg <matt@tidbits.com> wrote:

> 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.
--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

Jacob Fugal

10/27/2006 4:38:00 PM

0

On 10/27/06, matt neuburg <matt@tidbits.com> wrote:
> 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