How to get the value of a singleton class?

J

Joey Zhou

Here is a sample code:

str = "ABC"
class << str
p self
end

What I get is somthing like "#<Class:#<String:0x15d4bb0>>".

If "p str", there's an error message:

x.rb:3:in `singletonclass': undefined local variable or method `str' for
#<Class:#<String:0x1625bf8>> (NameError)

How can I get the value of str("ABC") within the class << str;...;end
block?

Thank you.

Joey
 
R

Robert Dober

Here is a sample code:

str =3D "ABC"
class << str
=A0p self
end

What I get is somthing like "#<Class:#<String:0x15d4bb0>>".

If "p str", there's an error message:

x.rb:3:in `singletonclass': undefined local variable or method `str' for
#<Class:#<String:0x1625bf8>> (NameError)

How can I get the value of str("ABC") within the class << str;...;end

your problem is that class << x...end is *not* a closure

x=3D 42
class << whatever # I disassociate x and whatever for the general case
x # No Method Error as we are *not* in a closure here
end

But there is a workaround, an idiom you will find quite often in Ruby
metaprogramming

x=3D42
class << whatever; self end.module_eval do
p x # Works like charm as this *is* a closure
end

Now if you were looking for a way to get from a singleton class of an
object to the object itself, I am not sure that this is possible.
I have not yet seen a case where I would have needed it, as I am
constructing my singletons myself;). Would you know such a usecase?
e.g. an API that passes in a singleton class and where it would be
useful to have access to the singlee - I just made this word up, I
guess.

HTH
Robert



--=20
The 1,000,000th fibonacci number contains '42' 2039 times; that is
almost 30 occurrences more than expected (208988 digits).
N.B. The 42nd fibonacci number does not contain '1000000' that is
almost the expected 3.0e-06 times.
 
J

Joey Zhou

Now if you were looking for a way to get from a singleton class of an
object to the object itself, I am not sure that this is possible.
I have not yet seen a case where I would have needed it, as I am
constructing my singletons myself;). Would you know such a usecase?
e.g. an API that passes in a singleton class and where it would be
useful to have access to the singlee - I just made this word up, I
guess.

Thank you for explanation.
The problem is not from a real program, but from my curiosity... I just
read the "singleton class" section of a Ruby book:)
 
R

Robert Dober

Thank you for explanation.
The problem is not from a real program, but from my curiosity... I just
read the "singleton class" section of a Ruby book:)

Than I am confident that

class << ...;self end.module_eval...

will be enough to continue your exploration :)

Cheers
R.
 
A

Adam Prescott

[Note: parts of this message were removed to make it a legal post.]

Now if you were looking for a way to get from a singleton class of an
object to the object itself, I am not sure that this is possible.

This should do the trick:
s = "" => ""
class << s
def test
1
end
end => nil
s.test => 1
meta = (class << s; self; end)
=> # said:
ObjectSpace.each_object(meta).to_a => [""]
_.first.object_id => 69092310
s.object_id
=> 69092310
 
7

7stud --

Robert Dober wrote in post #989182:
your problem is that class << x...end is *not* a closure

x= 42
class << whatever # I disassociate x and whatever for the general case
x # No Method Error as we are *not* in a closure here
end

But there is a workaround, an idiom you will find quite often in Ruby
metaprogramming

x=42
class << whatever; self end.module_eval do
p x # Works like charm as this *is* a closure
end

...but that is a ridiculous construct. You are creating a block for
module_eval() in order to see the local variable x. Well guess what?
You don't need a block to see x:

x = 42

class << whatever
self
end

puts x
 
7

7stud --

Joey Zhou wrote in post #989179:
Here is a sample code:

str = "ABC"
class << str
p self
end

What I get is somthing like "#<Class:#<String:0x15d4bb0>>".

If "p str", there's an error message:

x.rb:3:in `singletonclass': undefined local variable or method `str' for
#<Class:#<String:0x1625bf8>> (NameError)

How can I get the value of str("ABC") within the class << str;...;end
block?

By creating a method that does just that:

str = "ABC"

class << str
def show
puts self
end
end


str.show

Because str calls the show() method, inside show() self is equal to str.

You have to realize that when you write this:
str = "ABC"

class << str
p self
end

it's is the same as doing this:


class MyClass
p self
end

obj = MyClass.new

p obj

--output:--
MyClass
#<MyClass:0x401bfbf8>


...and wondering why 'p self' and 'p obj' don't produce the same
results. Inside a class, but outside of any method definitions, self is
equal to the class--that's why 'p self' gives you the class name.

When you do this:

class << str
..
...
end

you have opened up a class--what's called the 'eigenclass' of str.
Therefore, everywhere inside there, but outside any method definitions
self is the class, and will never be equal to str.
 
R

Robert Dober

Robert Dober wrote in post #989182:


What bothers us, is this

x=42
class << self
p x # x is *not* seen here
end

Although you call my code ridiculous, I agree with you, I think that
class << self should be a closure too, and optimized away if not used as such.
For now one cannot do better
Cheers
Robert
 
A

Aaron D. Gifford

...
What bothers us, is this

x=3D42
class << self
=A0p x # x is *not* seen here
end

Although you call my code ridiculous, I agree with you, I think that
class << self should be a closure too, and optimized away if not used as = such.
For now one cannot do better
Cheers
Robert
...

The fact that class and module definitions are NOT closures is
preferable in my opinion.

irb(main):001:0> foo =3D "FOO"
=3D> "FOO"
irb(main):002:0> class MyClass
irb(main):003:1> p foo
irb(main):004:1> end
NameError: undefined local variable or method `foo' for MyClass:Class
from (irb):3:in `<class:MyClass>'
from (irb):2
from /usr/local/bin/irb:12:in `<main>'
irb(main):005:0> module MyModule
irb(main):006:1> p foo
irb(main):007:1> end
NameError: undefined local variable or method `foo' for MyModule:Module
from (irb):6:in `<module:MyModule>'
from (irb):5
from /usr/local/bin/irb:12:in `<main>'

That just seems right.

Aaron out.
 
A

Aaron D. Gifford

And thanks for introducing me to ObjectSpace:

irb(main):001:0> foo = "FOO"
=> "FOO"
irb(main):002:0> class << foo
irb(main):003:1> p ObjectSpace.each_object(self).first
irb(main):004:1> end
"FOO"
=> "FOO"

I love learning something new.

Aaron out.
 
R

Robert Dober

That just seems right.

I do not really have a problem with this. However I feel that it is
really not for the language to decide if I want to do this or not. The
more restrictive way does not give me the opportunity to use closures
easily in my classes while it would still allow *not* to use them. BTW
I am quite convinced that this
is not a design choice, but I am prepared to stand corrected, I rather
think that it is quite a bit of work
to implement this without performance hits and as I do not really
recall [1] any demand of this I am
not surprised that it is not implemented.

[1] IIRC Zed Shaw asked once why the heck
def ... end
could (i) not be a closure and (ii) return the unbound method object.

I would like this very much, but I will not get it, I guess.

Cheers
Robert
 
B

Brian Candler

Robert Dober wrote in post #989410:
I do not really have a problem with this. However I feel that it is
really not for the language to decide if I want to do this or not. The
more restrictive way does not give me the opportunity to use closures
easily in my classes while it would still allow *not* to use them. BTW
I am quite convinced that this
is not a design choice

I think it *is* a design choice, because of the local variable/method
ambiguity.

If "class" and "def" did not start a new scope, then a bareword like "x"
*might* be a local variable within a closure. It would be extremely
difficult to tell; you'd have to read the entire program source code
back to the beginning of the file (assuming that 'load' and 'require'
started a new scope, otherwise it would be completely impossible).

With the current rules, given some code like

... lots of previous stuff
def foo
x
end

you can tell by inspection of method foo alone that x *must* be a method
call within foo; it's definitely not a local variable.
 
R

Robert Dober

Robert Dober wrote in post #989410:
I think it *is* a design choice, because of the local variable/method
ambiguity.

If "class" and "def" did not start a new scope, then a bareword like "x"
*might* be a local variable within a closure. It would be extremely
difficult to tell; you'd have to read the entire program source code
back to the beginning of the file (assuming that 'load' and 'require'
started a new scope, otherwise it would be completely impossible).
That is a very good point, I have used closure based programming, and
I have suffered from this.
I however think that I could have done much better than I did. I
missed some opportunities to refactor and introduce more abstraction.
From this experience I conclude that this would be a "feature" to use
with care and that care does not come as natural at first...

Now if you have long modules you will run into the same kind of
problem too. I do not think that Ruby can have a save barrier against
that.

However the parser could restrict closing over one level which could
be overcome with
constructs like this

x=3D42
class A
x=3Dx
def a; x end ...


However I get lost, what *really* could be a closure, I feel, is
class << x; .... end
as we are often in metaprogramming context here.

Cheers
Robert
With the current rules, given some code like

=A0 ... lots of previous stuff
=A0 def foo
=A0 =A0 x
=A0 end

you can tell by inspection of method foo alone that x *must* be a method
call within foo; it's definitely not a local variable.



--=20
The 1,000,000th fibonacci number contains '42' 2039 times; that is
almost 30 occurrences more than expected (208988 digits).
N.B. The 42nd fibonacci number does not contain '1000000' that is
almost the expected 3.0e-06 times.
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top