Initialize not being called on objects created from literals

O

Oliver Saunders

Initialize doesn't appear to get called.

class Object
def initialize
@foo = 'bar'
end
attr_reader :foo
end

a = Object.new # => #<Object:0x54c964 @foo="bar">
a.foo # => "bar"
'string'.foo # => nil
//.foo # => nil

I want to have //.foo and 'string.foo give me "bar" as they should. How
can I do that?
 
B

botp

Initialize doesn't appear to get called.

class Object
=A0def initialize
=A0 =A0@foo =3D 'bar'
=A0end
=A0attr_reader :foo
end

a =3D Object.new # =3D> #<Object:0x54c964 @foo=3D"bar">

see relation bw initialize and new
a.foo # =3D> "bar"
'string'.foo # =3D> nil
//.foo # =3D> nil

I want to have //.foo and 'string.foo give me "bar" as they should. How
can I do that?

try defining a method, eg
=3D> "bar"
 
R

Robert Klemme

Initialize doesn't appear to get called.

class Object
def initialize
@foo = 'bar'
end
attr_reader :foo
end

a = Object.new # => #<Object:0x54c964 @foo="bar">
a.foo # => "bar"
'string'.foo # => nil
//.foo # => nil

I want to have //.foo and 'string.foo give me "bar" as they should. How
can I do that?

A class needs to explicitly invoke #initialize of the super class. I
guess, since Object does not have any members by default String will not
do the invocation.

class A
def initialize
puts "A"
end
end

class B < A
def initialize
super
# or super() in this case
puts "B"
end
end

Having said that, it's generally not a too good idea to mess with built
in classes - even though you can. But you may produce unwanted side
effects.

Kind regards

robert
 
R

Rick DeNatale

A class needs to explicitly invoke #initialize of the super class. =A0I g= uess,
since Object does not have any members by default String will not do the
invocation.

This is true, see below
class A
=A0def initialize
=A0 =A0puts "A"
=A0end
end

class B < A
=A0def initialize
=A0 =A0super
=A0 =A0# or super() in this case
=A0 =A0puts "B"
=A0end
end

Having said that, it's generally not a too good idea to mess with built i= n
classes - even though you can. =A0But you may produce unwanted side effec=
ts.

But that's not the whole story. As the OP suspected, literals are
created by the parser without going through the normal initialization
route:

class Object
alias_method :eek:ld_initialize, :initialize
attr_reader :boo

def initialize(*args, &b) # !> redefining Object#initialize may
cause infinite loop
puts "Object#initialize"
old_initialize(*args, &b)
@boo =3D "who"
end
end

puts "calling String.new"
s1 =3D String.new
puts "back"
puts "s1.boo is #{s1.boo.inspect}"
puts "making String#initialize call super"
class String
alias_method :eek:ld_initialize, :initialize
def initialize(*args, &b)
super
puts "String#initialize"
old_initialize(*args, &b)
end

end

puts "calling String.new"
s2 =3D String.new
puts "s2.boo is #{s2.boo.inspect}"

puts "\"abc\".boo is #{"abc".boo.inspect}"

Produces the following

calling String.new
back
s1.boo is nil
making String#initialize call super
calling String.new
Object#initialize
String#initialize
s2.boo is "who"
"abc".boo is nil
untitled:5: warning: redefining Object#initialize may cause infinite loop

Note that warning pointing out a potential unwanted side effect.

--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
O

Oliver Saunders

Thanks Rick. I poked around a bit more after the last few posts made
here and couldn't find an answer. I started looking at the Ruby's C code
but couldn't really get any useful information from it. Despite this I'm
fairly confident what I wanted to do can't be done. But I managed to
work around it in the end with a solution that was actually surprisingly
simple.

For those interested to know what I was doing I was trying to implement
a layer for prototype-based OO in Ruby. Didn't really work though. As
far as I know (and please correct me if I'm wrong) Ruby doesn't allow
you to call a method redefining the meaning of self for the purpose of
the call (e.g. apply() in JS) and without this feature you can't really
implement this layer in any useful way.
 
R

Robert Klemme

For those interested to know what I was doing I was trying to implement
a layer for prototype-based OO in Ruby. Didn't really work though.

Please correct me if I am wrong, but you seem to mean

http://en.wikipedia.org/wiki/Prototype-based_programming

Would this approximate what you're after?

prototype = Object.new
class <<prototype
def foo
printf "%p %p\n", self, self.class
end
end
o1 = prototype.clone
o2 = prototype.clone
o1.foo
o2.foo
As
far as I know (and please correct me if I'm wrong) Ruby doesn't allow
you to call a method redefining the meaning of self for the purpose of
the call (e.g. apply() in JS) and without this feature you can't really
implement this layer in any useful way.

#instance_eval does exactly that: it temporarily sets self to point to a
particular instance.

But it seems apply() in JS world is used to do something else

http://www.devguru.com/Technologies/ecmascript/quickref/apply.html

Basically you would need it to call "super class" methods. A few
solutions come to mind. For construction you can do

def base
o = Object.new
class <<o
def base_meth
end
end
o
end

def derived
o = base
# alt: prototype.clone
class <<o
def derived_meth
end
end
o
end

If your search the archives I am pretty sure you'll find something about
prototype based OO in Ruby.

Kind regards

robert
 

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

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top