Mixing Constants into objects

G

gabriele renzi

Hi gurus and nubys,

is there a way to add a constant into an object which is not a module/class?

Basically what I'd like is some kind of append_features/include that
works on non-module objects.
Is my only chance to mess up with the singleton class by myself, or
there is some existing method for this?

Thanks in advance
 
D

David A. Black

Hi --

Hi gurus and nubys,

is there a way to add a constant into an object which is not a module/class?

Basically what I'd like is some kind of append_features/include that works on
non-module objects.

Is my only chance to mess up with the singleton class by myself, or there is
some existing method for this?

If I understand you correctly, I think Kernel#extend is what you need:

irb(main):001:0> s = ""
=> ""
irb(main):002:0> module M; X=1; end
=> 1
irb(main):003:0> s.extend(M)
=> ""
irb(main):004:0> (class << s; self; end)::X
=> 1

I think that's the closest thing corresponding to "adding a constant"
to an arbitrary object (adding it to the object's singleton class).


David
 
G

gabriele renzi

David A. Black ha scritto:
Hi --




If I understand you correctly, I think Kernel#extend is what you need:

irb(main):001:0> s = ""
=> ""
irb(main):002:0> module M; X=1; end
=> 1
irb(main):003:0> s.extend(M)
=> ""
irb(main):004:0> (class << s; self; end)::X
=> 1

I think that's the closest thing corresponding to "adding a constant"
to an arbitrary object (adding it to the object's singleton class).

well, ri explicitly says for #extend:
" Adds to _obj_ the instance methods from each module given as a
parameter"
and this is omitting Constants, which are available when something is
#include'd
See example:

I won't be able to access singleton class constants from the singleton
instance, it seems:
NameError: uninitialized constant Foo2::Bar
from (irb):12:in `barer'
from (irb):21

I don't understand why, actually.
 
D

David A. Black

Hi --

David A. Black ha scritto:

well, ri explicitly says for #extend:
" Adds to _obj_ the instance methods from each module given as a
parameter"
and this is omitting Constants, which are available when something is
#include'd

I'm not sure what you mean by "adding a constant to an object" if the
object isn't a Class or Module. For example:

obj = Object.new
obj.constants => no such method

All constants live in a class/module namespace. That's what I mean
when I say the closest you can get is adding it to an object's
singleton class.
See example:

I won't be able to access singleton class constants from the singleton
instance, it seems:

NameError: uninitialized constant Foo2::Bar

Where did "Foo2" come from? I get Foo::Bar :)
from (irb):12:in `barer'
from (irb):21

I don't understand why, actually.

I think it's this: when an instance method refers to a constant, that
constant is looked up in the class where the method is defined.
Therefore, in your example, Foo#barer looks for Foo::Bar.

So it's not the same as a method call, where it would be looked up in
the object's singleton class. I guess that's because constants really
belong to classes, not to objects generally. So when you ask for a
constant, the class you're in doesn't branch off and look in other
classes.

This may have to do with the way constant references are parsed, which
is kind of quasi-static.

Anyway, here's an illustration.

class Foo
def x
p X
end
end

foo = Foo.new

class << foo
X = 1
Y = 1
def y
p Y
end
end

foo.y => 1 (that's <foo's singleton class>::Y)
foo.x => uninitialized constant Foo::X
(foo's singleton class isn't involved)


David
 
D

Devin Mullins

As David said, the constant accessed in whatever class is specified by
the class...end block you're currently in. Example:

class Moo; MOO = 'hi' end
class Foo; MOO = 'burp' end
class Foo
def Moo.greet; p MOO end
end
class Moo
def Moo.bark; p MOO end
end

irb(main):009:0> Moo.bark
"hi"
irb(main):010:0> Moo.greet
"burp"

Constants share this property with class variables.

So, if you want to inject a factory into your class, you're going to
have to use a different method, or play around with const_set.

Devin
 
G

gabriele renzi

David A. Black ha scritto:
I'm not sure what you mean by "adding a constant to an object" if the
object isn't a Class or Module. For example:

obj = Object.new
obj.constants => no such method

All constants live in a class/module namespace. That's what I mean
when I say the closest you can get is adding it to an object's
singleton class.

you're right as usual :)
what I meant is adding them *somewhere* so that they're available to the
object. Basically I wondered if ruby had something able to do the
singleton class hackery withouth me noticing it, like extend does for
instance methods (but after reading the rest now I understand why this
can't work)

Where did "Foo2" come from? I get Foo::Bar :)

emh.. evil little creatures acting on my desktop, I'd say..
I think it's this: when an instance method refers to a constant, that
constant is looked up in the class where the method is defined.
Therefore, in your example, Foo#barer looks for Foo::Bar.

So it's not the same as a method call, where it would be looked up in
the object's singleton class. I guess that's because constants really
belong to classes, not to objects generally. So when you ask for a
constant, the class you're in doesn't branch off and look in other
classes.

ah, this makes a lot of sense, thanks

This may have to do with the way constant references are parsed, which
is kind of quasi-static.

mh.. maybe "lexical" is the better word ?
Anyway, here's an illustration.

class Foo
def x
p X
end
end

foo = Foo.new

class << foo
X = 1
Y = 1
def y
p Y
end
end

foo.y => 1 (that's <foo's singleton class>::Y)
foo.x => uninitialized constant Foo::X
(foo's singleton class isn't involved)

thanks for the explanation, this makes sense now.
 
D

David A. Black

Hi --

mh.. maybe "lexical" is the better word ?

I think it's more than that. What I should have said was: constant
references are resolved at parse-time, rather than run-time. At least
I think that's the case.


David
 
D

dave.burt

class Foo
def barer
bar.new
end
end
module M
class Bar
end
def bar() Bar end
end
foo=Foo.new
foo.extend M
foo.barer #=> #<Foo::Bar:0x2940eb8>
 
C

Caleb Clausen

=20
I think it's more than that. What I should have said was: constant
references are resolved at parse-time, rather than run-time. At least
I think that's the case.

Just how constant lookups work is something of a mystery to me in some
cases... it's clearly less dynamic than method lookup, but it is
run-time lookup, not compile time:

irb(main):001:0> class K
irb(main):002:1> Foo=3D1
irb(main):003:1> end=20
=3D> 1
irb(main):004:0> def fk; K::Foo end
=3D> nil
irb(main):005:0> fk
=3D> 1
irb(main):006:0> class K
irb(main):007:1> Foo=3D2
irb(main):008:1> end
(irb):7: warning: already initialized constant Foo
=3D> 2
irb(main):009:0> fk
=3D> 2
 
W

Wilson Bilkovich

=20
Just how constant lookups work is something of a mystery to me in some
cases... it's clearly less dynamic than method lookup, but it is
run-time lookup, not compile time:
=20
irb(main):001:0> class K
irb(main):002:1> Foo=3D1
irb(main):003:1> end
=3D> 1
irb(main):004:0> def fk; K::Foo end
=3D> nil
irb(main):005:0> fk
=3D> 1
irb(main):006:0> class K
irb(main):007:1> Foo=3D2
irb(main):008:1> end
(irb):7: warning: already initialized constant Foo
=3D> 2
irb(main):009:0> fk
=3D> 2

My (possibly totally off-base) understanding is that, as there is no
'compile' step in Ruby, the constants get 'burned' into the AST, as do
things like regular expression literals, between forward-slashes.=20
That would explain why they "look" like runtime evaluations, but they
aren't the same kind of citizen as variables.
 
J

Joel VanderWerf

Caleb said:
Just how constant lookups work is something of a mystery to me in some
cases... it's clearly less dynamic than method lookup, but it is
run-time lookup, not compile time:

irb(main):001:0> class K
irb(main):002:1> Foo=1
irb(main):003:1> end
=> 1
irb(main):004:0> def fk; K::Foo end
=> nil
irb(main):005:0> fk
=> 1
irb(main):006:0> class K
irb(main):007:1> Foo=2
irb(main):008:1> end
(irb):7: warning: already initialized constant Foo
=> 2
irb(main):009:0> fk
=> 2

Constant binding is normally static:

class K
Foo=1
end

def fk; K::Foo end

fk

class K
Foo=2
end

p fk # ==> 2

module M
class K
Foo=3
end
p fk # ==> 2
p K::Foo # ==> 3
end

# However, you can force dynamic constant binding:

def sfk; self::K::Foo; end

module M
p sfk # ==> 3
end
 

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,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top