#object_hexid

I

Intransition

Can anyone write a reliable Kernel#object_hexid, a method that returns
an object's id but in hex, just like Ruby's normal #inspect provides.

My attempts seems to break depending on the version of Ruby used.
 
D

Dominik Honnef

Can anyone write a reliable Kernel#object_hexid, a method that returns
an object's id but in hex, just like Ruby's normal #inspect provides.

My attempts seems to break depending on the version of Ruby used.

"0x%x" % (object_id << 1)

should work univerally, I guess.
 
B

Brian Candler

Thomas said:
Can anyone write a reliable Kernel#object_hexid, a method that returns
an object's id but in hex, just like Ruby's normal #inspect provides.

My attempts seems to break depending on the version of Ruby used.

Can you show the failing examples? Is the portability problem between
ruby 1.8.x and 1.9.x, or are you trying to make portable with JRuby,
Rubinius, MacRuby etc?

Is it important that object_hexid returns the same value as reported by
#inspect, or just some unique id?

The obvious would be something like:
=> "3faf23593bf4"

but I've not tested that on any more than MRI 1.8.7, and the hex ID is
not the same as #inspect:
=> "3faf2358e0b4"
 
I

Intransition

Can you show the failing examples? Is the portability problem between
ruby 1.8.x and 1.9.x, or are you trying to make portable with JRuby,
Rubinius, MacRuby etc?

That would be nice.

I recently got an error report from someone using 1.8.6:

1) Failure: test_object_hexid(TCKernel) [./test/core/kernel/
test_object_hexid.rb:8]:
<"#<Object:0x1a14ff4>"> expected but was
<"#<Object:0xa14ff4>">.

I know what's causing this in my current implementation, but I've been
down this road before -- I tweak the implementation to satisfy one
error report and another seems to crop up. So I was hoping someone
might have a definitive answer.
Is it important that object_hexid returns the same value as reported by
#inspect, or just some unique id?
Yes.

The obvious would be something like:


=3D> "3faf23593bf4"

but I've not tested that on any more than MRI 1.8.7, and the hex ID is
not the same as #inspect:


=3D> #<Foo:0x7f5e46b1c168>>> object_hexid(f)

=3D> "3faf2358e0b4"

Right. You have to shift the value one unit like Dominik's version.

At this point I think I am just going to go with the simple solution:

"0x" << (__id__ << 1).to_s(16)

Previous error reports seem to be 1.8.6 related, and at this point I
think I will only support 1.8.7+. Hopefully the above definition is
consistent for all implementations. I think it would be nice if this
method was already provided -- I find it helpful in cases where I
write a custom #inspect method, but still wish to imitate Ruby's usual
format.
 
C

Colin Bartlett

Can anyone write a reliable Kernel#object_hexid, a method that returns
an object's id but in hex, just like Ruby's normal #inspect provides.
My attempts seems to break depending on the version of Ruby used.
That's something I've wanted when I've been writing #inspect for a class, and
(for aesthetics!) I've wanted the object_id encoding in the default #inspect.
Give that there must (I assume) be a function in the underlying C or
Java (etc) code
to produce the object_id encoding, are there any reasons why that
should not also
be a method in Object?
(The C code for 1.9.1 seems to encode c pointer to the object?)

"0x%x" % (object_id << 1)
should work univerally, I guess.
It seems to work in Ruby 1.8.6 and 1.9.1, but not in JRuby? (See below.)

Is it important that object_hexid returns the same value as reported by
#inspect, or just some unique id?
I'm not sure (for me, anyway) it's vital that it's the same value as #inspect.
But I've been wondering why (as your code showed) that the hexid in #inspect
is different to #object_id.to_s(16). Can anyone give reasons?
(I've just had a quick look at the code in object.c, and a few other *.c
which included object_id or inspect/to_s, and nothing obvious struck me.
I must confess I found the code not easy to follow, but I only speak pidgin C.)

# code comparing the #inspect encoding of object_id with the object_id
class Q; end
q = Q.new
iid = q.inspect ; iid[-1, 1] = "" ; iid[0, 4] = ""
oid = q.object_id
puts "inspect #=> " + q.inspect
puts "inspect id #=> " + iid
puts "oid << 1 #=> 0x" + (oid << 1 ).to_s(16)
puts "Integer(iid) #=> " + Integer(iid).to_s
puts "oid #=> #=> " + oid.to_s

ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-mingw32]
inspect #=> #<Q:0x2205b80>
inspect id #=> 0x2205b80
oid << 1 #=> 0x2205b80
Integer(iid) #=> 35675008
oid #=> #=> 17837504

jruby 1.5.0.RC1 (ruby 1.8.7 patchlevel 249) (2010-04-14 0b08bc7)
(Java HotSpot(TM) Client VM 1.6.0_14) [x86-java]
inspect #=> #<Q:0x16fdac>
inspect id #=> 0x16fdac
oid << 1 #=> 0xfb8
Integer(iid) #=> 1506732
oid #=> #=> 2012
 
C

Caleb Clausen

I recently got an error report from someone using 1.8.6:

1) Failure: test_object_hexid(TCKernel) [./test/core/kernel/
test_object_hexid.rb:8]:
<"#<Object:0x1a14ff4>"> expected but was
<"#<Object:0xa14ff4>">.

I know what's causing this in my current implementation, but I've been
down this road before -- I tweak the implementation to satisfy one
error report and another seems to crop up. So I was hoping someone
might have a definitive answer.

Try this way?:

class Object
def hexid
Object.instance_method:)inspect).bind(self).call[/:(.*?)[> ]/,1]
end
end

Ugly, but seems like it ought to be fairly universal. Well, it won't
work with BlankSlate/BasicObject, but other than that....
 
C

Caleb Clausen

Try this way?:

class Object
def hexid
Object.instance_method:)inspect).bind(self).call[/:(.*?)[> ]/,1]
end
end

Ugly, but seems like it ought to be fairly universal. Well, it won't
work with BlankSlate/BasicObject, but other than that....

Oh, but I see now that this doesn't work for many builtins like Array,
Hash, Integer, Float, String, true, Symbol.... I didn't expect that.
 
C

Charles Oliver Nutter

I recently got an error report from someone using 1.8.6:

=C2=A01) Failure: test_object_hexid(TCKernel) [./test/core/kernel/
test_object_hexid.rb:8]:
=C2=A0<"#<Object:0x1a14ff4>"> expected but was
=C2=A0<"#<Object:0xa14ff4>">.

I know what's causing this in my current implementation, but I've been
down this road before -- I tweak the implementation to satisfy one
error report and another seems to crop up. So I was hoping someone
might have a definitive answer.

I think you're going to be SOL expecting these values to always match
up across implementations. They are fortunately the same or similar in
C Ruby versions because C Ruby uses the pointer address of the object
for that hex number. On implementations where objects can move in
memory, that value is almost always going to be calculated and
potentially not even unique.

In JRuby, the inspect value is based on the "identity hashcode" of the
object, which is the default hashcode value the object would have it
if did not override and provide its own hashcode. It is not guaranteed
to be unique. Because of that, JRuby uses a strictly-increasing
counter for object_id's as they are requested, and so object_id is
entirely unrelated to the inspect hash string.

I suspect other implementations with relocating objects will have
similar limitations on the uniqueness and equivalence of these various
values.

If you really want a unique hexid you can use for a given object,
calculate it and stuff it into the object when it's first requested:

class Object
def hexid
# not thread-safe, but wasting an ID isn't a big deal
@hexid ||=3D Object.calculate_hexid
@hexid.to_s(16)
end

def self.calculate_hexid
# appropriate mutexing should surround this
@next_hexid +=3D 1
end
end

Or on an impl like JRuby, where object_id is guaranteed not to produce
a duplicate value (or at least, not up to 2^64 object_id's), just use
object_id directly.

I guarantee this won't ever work in JRuby and may not work on anything
but C Ruby. I think you're asking too much of that inspect value.

Can you describe *why* you need this behavior?

- Charlie
 
I

Intransition

I think you're going to be SOL expecting these values to always match
up across implementations. They are fortunately the same or similar in
C Ruby versions because C Ruby uses the pointer address of the object
for that hex number. On implementations where objects can move in
memory, that value is almost always going to be calculated and
potentially not even unique.

In JRuby, the inspect value is based on the "identity hashcode" of the
object, which is the default hashcode value the object would have it
if did not override and provide its own hashcode. It is not guaranteed
to be unique. Because of that, JRuby uses a strictly-increasing
counter for object_id's as they are requested, and so object_id is
entirely unrelated to the inspect hash string.

I suspect other implementations with relocating objects will have
similar limitations on the uniqueness and equivalence of these various
values.

If you really want a unique hexid you can use for a given object,
calculate it and stuff it into the object when it's first requested:

class Object
=A0 def hexid
=A0 =A0 # not thread-safe, but wasting an ID isn't a big deal
=A0 =A0 @hexid ||=3D Object.calculate_hexid
=A0 =A0 @hexid.to_s(16)
=A0 end

=A0 def self.calculate_hexid
=A0 =A0 # appropriate mutexing should surround this
=A0 =A0 @next_hexid +=3D 1
=A0 end
end

Or on an impl like JRuby, where object_id is guaranteed not to produce
a duplicate value (or at least, not up to 2^64 object_id's), just use
object_id directly.





I guarantee this won't ever work in JRuby and may not work on anything
but C Ruby. I think you're asking too much of that inspect value.

Can you describe *why* you need this behavior?

I don't expect the values to match up across implementations, I just
want a reliable way to get a value for a given implementation. My only
need is to emulate #inspect when I am customizing it. E.g.

class MyHash << Hash
def inspect
"#<#{self.class}:#{object_hexid} #{super}>"
end
end

So, again, there's no need for it to match across implementations. I
just need a method that will return whatever value the implementation
is using.
 

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,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top