Constant lookup starting in superclass, not derived class

C

Chris Roos

I'm no doubt missing something obvious but I found this a little
confusing. I would have expected the constant lookup to start in Bar
and therefore succeed. Instead, it appears to start in Base where Foo
is not defined.

class Base
def foo
p Foo
end
end

class Bar < Base
class Foo
end
end

Bar.new.foo
# ~> -:3:in `foo': uninitialized constant Base::Foo (NameError)
# ~> from -:12

Can anyone explain what is happening please?

Cheers,

Chris
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Constant lookup starting in superclass, not derived class"

|I'm no doubt missing something obvious but I found this a little
|confusing. I would have expected the constant lookup to start in Bar
|and therefore succeed. Instead, it appears to start in Base where Foo
|is not defined.
|
|class Base
| def foo
| p Foo
| end
|end

use "self.class::Foo" instead of plain "Foo".

matz.
 
R

Robert Klemme

Chris said:
I'm no doubt missing something obvious but I found this a little
confusing. I would have expected the constant lookup to start in Bar
and therefore succeed. Instead, it appears to start in Base where Foo
is not defined.

class Base
def foo
p Foo
end
end

class Bar < Base
class Foo
end
end

Bar.new.foo
# ~> -:3:in `foo': uninitialized constant Base::Foo (NameError)
# ~> from -:12

Can anyone explain what is happening please?

Foo is not in the scope of Base so it cannot be looked up the way you
did it. See Matz's explanation how to access it nevertheless.
Generally this form of dependency is not desirable, because the base
class should be self contained and not depend on any sub classes. In
Java you could make Base abstract and add an abstract method that will
return a Class instance - but in Ruby there are no abstract classes.

Kind regards

robert
 
L

Logan Capaldo

I'm no doubt missing something obvious but I found this a little
confusing. I would have expected the constant lookup to start in Bar
and therefore succeed. Instead, it appears to start in Base where Foo
is not defined.

class Base
def foo
p Foo
end
end

class Bar < Base
class Foo
end
end

Bar.new.foo
# ~> -:3:in `foo': uninitialized constant Base::Foo (NameError)
# ~> from -:12

Can anyone explain what is happening please?
Constants, unlike methods and instance variables, are "quasi"-lexicaly
scoped. (I say "quasi" because a sub class can assign to a constant
without munging its parent class's constant) One way of getting around
this particular situation is to use #const_get. e.g.:

class Base
def foo
p self.class.const_get('Foo')
end
end
 
C

Chris Roos

Do you have any suggestions of alternative implementation?

I'd rather not use the self.class.const_get method as it clutters the
code somewhat.

I wonder if I'm trying to refactor two seemingly identical methods
that are in fact different.

class Main1
def Foo; end
def foo
Foo.new
end
end

class Main2
def Foo; end
def foo
Foo.new
end
end

At this point, I created a superclass to hold the common foo method
definition. However, if I had the fully qualified namespace for Foo
(Main1::Foo and Main2::Foo) in each method they would be different and
I wouldn't have moved them. Maybe that is part of my problem.

I understand the point about the base class depending on child classes
not being desirable. What about a module relying on constants defined
elsewhere (does the same apply)?

module Base
def foo
p Foo.new
end
end

class Foo
include Base
class Foo
end
end

Thanks again,

Chris
 
R

Robert Klemme

Chris said:
Do you have any suggestions of alternative implementation?

Depends on what you want to do. If you just want to create instances
then you can just use a method.

class Base
def something
f = create_foo
# use f
end
end

class Derived < Base
class Foo
end

def create_foo(*a,&b)
Foo.new(*a,&b)
end
end

Or, if you want to do it more fancy you can define create_foo in the
base class and have it return nil or raise an exception.

Kind regards

robert


PS: Please don't top post and trim quotings - that way others can easier
follow threads here.
 
P

Paul Battley

PS: Please don't top post and trim quotings - that way others can easier
follow threads here.

Or to put it more clearly, 'please trim quotations and don't top post.'

Drifting wildly away from the topic, the ambiguity in the original
request reminds me of the signs posted by Southwark Council on some of
their properties: 'Do not exercise or allow your dog to foul the
estate.' (People seem to follow the first half better than the
second.)

Paul.
 

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top