Determining whether an object is an immediate?

This is be best I could come up with for determining whether an
object is an immediate (Fixnum, Symbol, false, true, nil,
others?):

begin
  obj.clone
  # clone worked - not an immediate
rescue TypeError
  # clone failed - immediate
end

Anybody have a better way? If the above is the best, seems
like an Object#immediate? would be nice to have.

···

__________________________________
Yahoo! FareChase: Search multiple travel sites in one click.
http://farechase.yahoo.com

Eric Mahurin wrote:

This is be best I could come up with for determining whether an
object is an immediate (Fixnum, Symbol, false, true, nil,
others?):

begin
  obj.clone
  # clone worked - not an immediate
rescue TypeError
  # clone failed - immediate
end

Anybody have a better way? If the above is the best, seems
like an Object#immediate? would be nice to have.

I seem to remember that begin/rescue is extremely slow, so since we know up front what all the immediate classes are I guessed that it would be faster just to test for them in a case expression. I put together a benchmark test that confirms my suspicion. Results first, then the test. I ran the test on my Powerbook.

me$ ruby test.rb
         user system total real
rescue 2.040000 0.130000 2.170000 ( 2.527118)
case 0.220000 0.010000 0.230000 ( 0.240941)

Here's the test code. The OBJECTS array contains 5 immediate objects and 5 non-immediate objects. Of course, with the "rescue" approach you get a clone of the non-immediate object and in the "case" approach you don't, but I'm assuming that you don't need the clone.

require 'benchmark'
include Benchmark

OBJECTS = [1, , :sym, "astring", true, {}, false, 1..3, nil, /x/]
ITERATIONS = 10000

bm(2) do |x|
  x.report("rescue") do
    ITERATIONS.times do
      OBJECTS.each do |obj|
        begin
          obj.clone
        rescue
          # nothing
        end
      end
    end
  end
  
  x.report("case ") do
    ITERATIONS.times do
      OBJECTS.each do |obj|
        case obj
          when Fixnum, Symbol, TrueClass, FalseClass, NilClass
            # nothing
          else
            # nothing
        end
      end
    end
  end
    
end

Eric Mahurin wrote:

This is be best I could come up with for determining whether an
object is an immediate (Fixnum, Symbol, false, true, nil,
others?):

begin
  obj.clone
  # clone worked - not an immediate
rescue TypeError
  # clone failed - immediate
end

Anybody have a better way? If the above is the best, seems
like an Object#immediate? would be nice to have.

I wonder why you need this. I suspect becuase you're using #clone in a
general situation and want to test to make sure before doing so?
Perhaps not. But in either case, I'm not sure why #clone (or #dup) just
doesn't return self for these. I mean if they are immediate and hence
there is but "one", then why isn't the one a satisfactory clone? Is
there a good reason not to do this?

Thanks,
T.

The clone test does not work. Reason? There are plenty of
non-immediate objects that won't clone like Float and Bignum
instances. One test you could use is the singleton class:

# Should raise a TypeError
class << :immediate_object; end

Of course immediate object could also be found missing from
ObjectSpace, but I would imagine that test to be very slow.

May I ask why you need to know the immediacy of an object?

Brian.

···

On 10/29/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:

This is be best I could come up with for determining whether an
object is an immediate (Fixnum, Symbol, false, true, nil,
others?):

begin
  obj.clone
  # clone worked - not an immediate
rescue TypeError
  # clone failed - immediate
end

Anybody have a better way? If the above is the best, seems
like an Object#immediate? would be nice to have.

you think #clone is slow, try (you could test for adding singleton
methods, that would be even slower!):

+ x.report("objSpace ") do
+ ITERATIONS.times do
+ OBJECTS.each do |obj|
+ begin
+ if ObjectSpace.include?(obj)
+ # nothin
+ end
+ rescue TypeError
+ # noting
+ end
+ end
+ end
+ end

Timothy Hunter wrote:

···

Eric Mahurin wrote:
> This is be best I could come up with for determining whether an
> object is an immediate (Fixnum, Symbol, false, true, nil,
> others?):
>

The clone test does not work. Reason? There are plenty of
non-immediate objects that won't clone like Float and Bignum
instances.

Didn't notice that. I wonder why they didn't make this work. If it were up
to me, I would make all immutable objects (including immediate objects)
return self for clone.

One test you could use is the singleton class:

# Should raise a TypeError
class << :immediate_object; end

I thought of that one previously too. The problem with this one is that for
non-immediates, it will create singleton/meta classes for them when I don't
need them. Maybe not that big a deal.

Of course immediate object could also be found missing from

ObjectSpace, but I would imagine that test to be very slow.

Probably the best test for now, but slow.

May I ask why you need to know the immediacy of an object?

Performance. I don't really "need" to know - since this is an optimization.
I'm doing some code generation (parser generator). When I'm given an
immediate object instead of storing it in a variable and having the code use
the variable, I want immediates to appear directly in the code (because
there is no object creation penalty and I know it is immutable). My
generated code doesn't reassign these variables (but it may modify the
objects) so this works.

Looking at the C code (ruby.h: SPECIAL_CONST_P), another option would be
this:

id = obj.__id__
(id&3).nonzero? || (id&~4).zero?

As long as ruby continues to encode immediates as it does now (can add
more), this should work.

···

On 10/31/05, Brian Mitchell <binary42@gmail.com> wrote:

It is slow, but this is probably one of the better definitions
of what an immediate is - whether it exists in ObjectSpace or
not.

Here's another solution:

class Object; def immediate?;false;end;end
class Fixnum; def immediate?;true; end;end
class Symbol; def immediate?;true; end;end
class NilClass; def immediate?;true; end;end
class FalseClass;def immediate?;true; end;end
class TrueClass; def immediate?;true; end;end

···

--- Gene Tani <gene.tani@gmail.com> wrote:

you think #clone is slow, try (you could test for adding
singleton
methods, that would be even slower!):

+ x.report("objSpace ") do
+ ITERATIONS.times do
+ OBJECTS.each do |obj|
+ begin
+ if ObjectSpace.include?(obj)
+ # nothin
+ end
+ rescue TypeError
+ # noting
+ end
+ end
+ end
+ end

Timothy Hunter wrote:
> Eric Mahurin wrote:
> > This is be best I could come up with for determining
whether an
> > object is an immediate (Fixnum, Symbol, false, true, nil,
> > others?):
> >

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

################ benchmark, round 2
OBJECTS = [1, 3.14159, , :sym, "astring", true, {}, false, 1..3, nil,
/x/]
ITERATIONS = 10000 ## change
bm(2) do |x|
        x.report("VClass ") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                                begin
                                        class<<obj; end
                                rescue TypeError
                                        # nothing
        end; end; end; end
        x.report("=== ") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                                case obj
                                        when Fixnum, Symbol, TrueClass,
FalseClass, NilClass
                                                # nothing
                                        else
                                                # nothing
        end; end; end; end
        x.report("objSpac") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                            begin
                                if ObjectSpace.include?(obj)
                                   # nothin
                                end
                            rescue TypeError
                                # noting
        end; end; end;end
end

···

######################
        user system total real
VClass 0.937000 0.000000 0.937000 ( 0.937000)
=== 0.219000 0.000000 0.219000 ( 0.219000)
objSpac 4.734000 0.000000 4.734000 ( 4.734000)

Eric Mahurin wrote:

On 10/31/05, Brian Mitchell <binary42@gmail.com> wrote:

> The clone test does not work. Reason? There are plenty of
> non-immediate objects that won't clone like Float and Bignum
> instances.

Didn't notice that. I wonder why they didn't make this work. If it were up
to me, I would make all immutable objects (including immediate objects)
return self for clone.

One test you could use is the singleton class:
>
> # Should raise a TypeError
> class << :immediate_object; end

I thought of that one previously too. The problem with this one is that for
non-immediates, it will create singleton/meta classes for them when I don't
need them. Maybe not that big a deal.

Of course immediate object could also be found missing from
> ObjectSpace, but I would imagine that test to be very slow.

Probably the best test for now, but slow.

May I ask why you need to know the immediacy of an object?
>

Performance. I don't really "need" to know - since this is an optimization.
I'm doing some code generation (parser generator). When I'm given an
immediate object instead of storing it in a variable and having the code use
the variable, I want immediates to appear directly in the code (because
there is no object creation penalty and I know it is immutable). My
generated code doesn't reassign these variables (but it may modify the
objects) so this works.

Looking at the C code (ruby.h: SPECIAL_CONST_P), another option would be
this:

id = obj.__id__
(id&3).nonzero? || (id&~4).zero?

As long as ruby continues to encode immediates as it does now (can add
more), this should work.

I'm confused, don't you need to only check that least signif. bit is 1,
whereas #zero? and #nonzero? look at everything except LSB on a Fixnum,
once they've figured out whether object is Fixnum, Float or Bignum?

Also, i noticed that python people noticed about tagged integers:
http://mail.python.org/pipermail/python-dev/2004-July/046139.html

Eric Mahurin wrote:

···

Looking at the C code (ruby.h: SPECIAL_CONST_P), another option would be
this:

id = obj.__id__
(id&3).nonzero? || (id&~4).zero?

As long as ruby continues to encode immediates as it does now (can add
more), this should work.

Here is one-line version:

[Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass].each { |c|
c.instance_eval { define_method(:immediate?) { true } } }

···

On 10/31/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:

It is slow, but this is probably one of the better definitions
of what an immediate is - whether it exists in ObjectSpace or
not.

Here's another solution:

class Object; def immediate?;false;end;end
class Fixnum; def immediate?;true; end;end
class Symbol; def immediate?;true; end;end
class NilClass; def immediate?;true; end;end
class FalseClass;def immediate?;true; end;end
class TrueClass; def immediate?;true; end;end

--
http://nohmad.sub-port.net

Hi,

···

----- Original Message -----
From: "Eric Mahurin" <eric_mahurin@yahoo.com>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Monday, October 31, 2005 12:57 AM
Subject: Re: determining whether an object is an immediate?

It is slow, but this is probably one of the better definitions
of what an immediate is - whether it exists in ObjectSpace or
not.

Here's another solution:

class Object; def immediate?;false;end;end
class Fixnum; def immediate?;true; end;end
class Symbol; def immediate?;true; end;end
class NilClass; def immediate?;true; end;end
class FalseClass;def immediate?;true; end;end
class TrueClass; def immediate?;true; end;end

This would be better:

class Object
  def immediate?
    [Fixnum, Symbol, NilClass, FalseClass, TrueClass].include?(self.class)
  end
end

Regards,

Park Heesob

(pls ignore prior 2 posts, I'm still mulling over how __id__'s work for
immed. values )
############## benchmark round 3
OBJECTS = [1, 3.14159, , :sym, "astring", true, {}, false, 1..3, nil,
/x/]
ITERATIONS = 10000
IMMED_CLASSES=[Fixnum, Symbol, TrueClass, FalseClass, NilClass]
bm(2) do |x|
        x.report("VClass ") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                                begin
                                        class<<obj; end
                                rescue TypeError
                                        # nothing
        end; end; end; end
        x.report("=== ") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                                if obj=== IMMED_CLASSES
                                                # nothing
                                else
                                                # nothing
        end; end; end; end
        x.report("===2 ") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                                if IMMED_CLASSES===obj
                                                # nothing
                                else
                                                # nothing
        end; end; end; end
        x.report("cl_incl") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                                if IMMED_CLASSES.include?(obj.class)
                                                # nothing

                                else
                                                # nothing

        end; end; end; end

        x.report("objSpac") do
                ITERATIONS.times do
                        OBJECTS.each do |obj|
                            begin
                                if ObjectSpace.include?(obj)
                                   # nothin
                                end
                            rescue TypeError
                                # noting
        end; end; end;end
end

···

######################
WinXP, 1.8.2 from 1-click installer, cut/pasted out of Komodo 3.5 alpha

        user system total real
VClass 0.922000 0.000000 0.922000 ( 0.922000)
=== 0.672000 0.000000 0.672000 ( 0.672000)
===2 0.219000 0.000000 0.219000 ( 0.219000)
cl_incl 0.187000 0.000000 0.187000 ( 0.187000)
objSpac 4.453000 0.000000 4.453000 ( 4.453000)
Gene Tani wrote:

I'm confused,

> It is slow, but this is probably one of the better definitions
> of what an immediate is - whether it exists in ObjectSpace or
> not.
>
> Here's another solution:
>
> class Object; def immediate?;false;end;end
> class Fixnum; def immediate?;true; end;end
> class Symbol; def immediate?;true; end;end
> class NilClass; def immediate?;true; end;end
> class FalseClass;def immediate?;true; end;end
> class TrueClass; def immediate?;true; end;end
>

Here is one-line version:

[Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass].each { |c|
c.instance_eval { define_method(:immediate?) { true } } }

--
http://nohmad.sub-port.net

Ouch, except Object:

[Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass].each {

c> c.instance_eval { define_method(:immediate?) { (Object == self) ?

false : true } } }
#=> [Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass]

Fixnum.immediate?

#=> true

Object.immediate?

#=> false

···

On 10/31/05, Gyoung-Yoon Noh <nohmad@gmail.com> wrote:

On 10/31/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:

--
http://nohmad.sub-port.net

Interesting, except the Object version needs to return false:

[Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass].each { |c|
c.instance_eval { define_method(:immediate?) { not c==Object } } }

Ryan

···

On 10/30/05, Gyoung-Yoon Noh <nohmad@gmail.com> wrote:

Here is one-line version:

[Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass].each { |c|
c.instance_eval { define_method(:immediate?) { true } } }

But also:

irb(main):007:0> 'string'.immediate?
=> true
irb(main):008:0> .immediate?
=> true
irb(main):009:0> Array.immediate?
=> true

Yours returns true for everything except Object. The other version I
posted is correct.

Ryan

···

On 10/30/05, Gyoung-Yoon Noh <nohmad@gmail.com> wrote:

Ouch, except Object:

>> [Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass].each {
>c> c.instance_eval { define_method(:immediate?) { (Object == self) ?
false : true } } }
#=> [Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass]
>> Fixnum.immediate?
#=> true
>> Object.immediate?
#=> false

Right. 'self' should not be there. Thanks for correcting.

···

On 10/31/05, Ryan Leavengood <leavengood@gmail.com> wrote:

On 10/30/05, Gyoung-Yoon Noh <nohmad@gmail.com> wrote:
>
> Ouch, except Object:
>
> >> [Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass].each {
> >c> c.instance_eval { define_method(:immediate?) { (Object == self) ?
> false : true } } }
> #=> [Object, Fixnum, Symbol, NilClass, FalseClass, TrueClass]
> >> Fixnum.immediate?
> #=> true
> >> Object.immediate?
> #=> false

But also:

irb(main):007:0> 'string'.immediate?
=> true
irb(main):008:0> .immediate?
=> true
irb(main):009:0> Array.immediate?
=> true

Yours returns true for everything except Object. The other version I
posted is correct.

Ryan

--
http://nohmad.sub-port.net