#object_hexid

#1

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.

#2

On [Sat, 24.04.2010 22:16], Intransition wrote:

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.

#3

Thomas S. wrote:

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:

module Kernel
def object_hexid(o)
o.object_id.to_s(16)
end
end
=> nil

object_hexid("")
=> “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:

class Foo; end
=> nil

f = Foo.new
=> #Foo:0x7f5e46b1c168

object_hexid(f)
=> “3faf2358e0b4”

#4

On Apr 24, 9:31 am, Brian C. removed_email_address@domain.invalid wrote:

Thomas S. wrote:

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?

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.

=> “3faf23593bf4”
=> “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.

#5

On 4/24/10, Intransition removed_email_address@domain.invalid wrote:

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…

#6

On Sat, Apr 24, 2010 at 2:16 PM, Intransition removed_email_address@domain.invalid
wrote:

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?)

On Sat, Apr 24, 2010 at 2:22 PM, Dominik H. removed_email_address@domain.invalid
wrote:

“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.)

On Sat, Apr 24, 2010 at 2:31 PM, Brian C. removed_email_address@domain.invalid
wrote:

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™ Client VM 1.6.0_14) [x86-java]
inspect #=> #<Q:0x16fdac>
inspect id #=> 0x16fdac
oid << 1 #=> 0xfb8
Integer(iid) #=> 1506732
oid #=> #=> 2012

#7

On 4/24/10, Caleb C. removed_email_address@domain.invalid wrote:

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.

#8

On Apr 25, 3:52 am, Charles Oliver N. removed_email_address@domain.invalid wrote:

to be unique. Because of that, JRuby uses a strictly-increasing
class Object
end

Yes.

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.

#9

On Sat, Apr 24, 2010 at 9:09 AM, Intransition removed_email_address@domain.invalid
wrote:

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 ||= Object.calculate_hexid
@hexid.to_s(16)
end

def self.calculate_hexid
# appropriate mutexing should surround this
@next_hexid += 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.

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

Yes.

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