Class: BasicObject

Inherits:
Qnil show all
Defined in:
object.c,
class.c,
object.c

Overview

BasicObject is the parent class of all classes in Ruby. It's an explicit blank class.

BasicObject can be used for creating object hierarchies independent of Ruby's object hierarchy, proxy objects like the Delegator class, or other uses where namespace pollution from Ruby's methods and classes must be avoided.

To avoid polluting BasicObject for other users an appropriately named subclass of BasicObject should be created instead of directly modifying BasicObject:

class MyObjectSystem < BasicObject
end

BasicObject does not include Kernel (for methods like puts) and BasicObject is outside of the namespace of the standard library so common classes will not be found without using a full class path.

A variety of strategies can be used to provide useful portions of the standard library to subclasses of BasicObject. A subclass could include Kernel to obtain puts, exit, etc. A custom Kernel-like module could be created and included or delegation can be used via #method_missing:

class MyObjectSystem < BasicObject
  DELEGATE = [:puts, :p]

  def method_missing(name, *args, &block)
    return super unless DELEGATE.include? name
    ::Kernel.send(name, *args, &block)
  end

  def respond_to_missing?(name, include_private = false)
    DELEGATE.include?(name) or super
  end
end

Access to classes and modules from the Ruby standard library can be obtained in a BasicObject subclass by referencing the desired constant from the root like ::File or ::Enumerator. Like #method_missing, #const_missing can be used to delegate constant lookup to Object:

class MyObjectSystem < BasicObject
  def self.const_missing(name)
    ::Object.const_get(name)
  end
end

Direct Known Subclasses

Object, Ractor::MovedObject

Instance Method Summary collapse

Constructor Details

#initializeObject (private)

call-seq:

BasicObject.new

Returns a new BasicObject.


1140
1141
1142
1143
1144
# File 'object.c', line 1140

static VALUE
rb_obj_dummy0(VALUE _)
{
    return rb_obj_dummy();
}

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol[, *args]) ⇒ Object (private)

Invoked by Ruby when obj is sent a message it cannot handle. symbol is the symbol for the method called, and args are any arguments that were passed to it. By default, the interpreter raises an error when this method is called. However, it is possible to override the method to provide more dynamic behavior. If it is decided that a particular method should not be handled, then super should be called, so that ancestors can pick up the missing method. The example below creates a class Roman, which responds to methods with names consisting of roman numerals, returning the corresponding integer values.

class Roman
  def roman_to_int(str)
    # ...
  end

  def method_missing(symbol, *args)
    str = symbol.id2name
    begin
      roman_to_int(str)
    rescue
      super(symbol, *args)
    end
  end
end

r = Roman.new
r.iv      #=> 4
r.xxiii   #=> 23
r.mm      #=> 2000
r.foo     #=> NoMethodError

734
735
736
737
738
739
740
# File 'vm_eval.c', line 734

static VALUE
rb_method_missing(int argc, const VALUE *argv, VALUE obj)
{
    rb_execution_context_t *ec = GET_EC();
    raise_method_missing(ec, argc, argv, obj, ec->method_missing_reason);
    UNREACHABLE_RETURN(Qnil);
}

Instance Method Details

#!Boolean

Boolean negate.

Returns:

  • (Boolean)

253
254
255
256
257
# File 'object.c', line 253

MJIT_FUNC_EXPORTED VALUE
rb_obj_not(VALUE obj)
{
    return RTEST(obj) ? Qfalse : Qtrue;
}

#!=(other) ⇒ Boolean

Returns true if two objects are not-equal, otherwise false.

Returns:

  • (Boolean)

269
270
271
272
273
274
# File 'object.c', line 269

MJIT_FUNC_EXPORTED VALUE
rb_obj_not_equal(VALUE obj1, VALUE obj2)
{
    VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
    return RTEST(result) ? Qfalse : Qtrue;
}

#==(other) ⇒ Boolean #equal?(other) ⇒ Boolean #eql?(other) ⇒ Boolean

Equality — At the Object level, #== returns true only if obj and other are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.

Unlike #==, the #equal? method should never be overridden by subclasses as it is used to determine object identity (that is, a.equal?(b) if and only if a is the same object as b):

obj = "a"
other = obj.dup

obj == other      #=> true
obj.equal? other  #=> false
obj.equal? obj    #=> true

The #eql? method returns true if obj and other refer to the same hash key. This is used by Hash to test members for equality. For any pair of objects where #eql? returns true, the #hash value of both objects must be equal. So any subclass that overrides #eql? should also override #hash appropriately.

For objects of class Object, #eql? is synonymous with #==. Subclasses normally continue this tradition by aliasing #eql? to their overridden #== method, but there are exceptions. Numeric types, for example, perform type conversion across #==, but not across #eql?, so:

1 == 1.0     #=> true
1.eql? 1.0   #=> false

Overloads:

  • #==(other) ⇒ Boolean

    Returns:

    • (Boolean)
  • #equal?(other) ⇒ Boolean

    Returns:

    • (Boolean)
  • #eql?(other) ⇒ Boolean

    Returns:

    • (Boolean)

234
235
236
237
238
239
# File 'object.c', line 234

MJIT_FUNC_EXPORTED VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
    if (obj1 == obj2) return Qtrue;
    return Qfalse;
}

#__id__Object

call-seq:

obj.__id__       -> integer
obj.object_id    -> integer

Returns an integer identifier for obj.

The same number will be returned on all calls to object_id for a given object, and no two active objects will share an id.

Note: that some objects of builtin classes are reused for optimization. This is the case for immediate values and frozen string literals.

BasicObject implements __id__, Kernel implements object_id.

Immediate values are not passed by reference but are passed by value: nil, true, false, Fixnums, Symbols, and some Floats.

Object.new.object_id  == Object.new.object_id  # => false
(21 * 2).object_id    == (21 * 2).object_id    # => true
"hello".object_id     == "hello".object_id     # => false
"hi".freeze.object_id == "hi".freeze.object_id # => true

4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
# File 'gc.c', line 4115

VALUE
rb_obj_id(VALUE obj)
{
    /*
     *                32-bit VALUE space
     *          MSB ------------------------ LSB
     *  false   00000000000000000000000000000000
     *  true    00000000000000000000000000000010
     *  nil     00000000000000000000000000000100
     *  undef   00000000000000000000000000000110
     *  symbol  ssssssssssssssssssssssss00001110
     *  object  oooooooooooooooooooooooooooooo00        = 0 (mod sizeof(RVALUE))
     *  fixnum  fffffffffffffffffffffffffffffff1
     *
     *                    object_id space
     *                                       LSB
     *  false   00000000000000000000000000000000
     *  true    00000000000000000000000000000010
     *  nil     00000000000000000000000000000100
     *  undef   00000000000000000000000000000110
     *  symbol   000SSSSSSSSSSSSSSSSSSSSSSSSSSS0        S...S % A = 4 (S...S = s...s * A + 4)
     *  object   oooooooooooooooooooooooooooooo0        o...o % A = 0
     *  fixnum  fffffffffffffffffffffffffffffff1        bignum if required
     *
     *  where A = sizeof(RVALUE)/4
     *
     *  sizeof(RVALUE) is
     *  20 if 32-bit, double is 4-byte aligned
     *  24 if 32-bit, double is 8-byte aligned
     *  40 if 64-bit
     */

    return rb_find_object_id(obj, cached_object_id);
}

#send(symbol[, args...]) ⇒ Object #__send__(symbol[, args...]) ⇒ Object #send(string[, args...]) ⇒ Object #__send__(string[, args...]) ⇒ Object

Invokes the method identified by symbol, passing it any

arguments specified.
When the method is identified by a string, the string is converted
to a symbol.

BasicObject implements +__send__+, Kernel implements +send+.
<code>__send__</code> is safer than +send+
when _obj_ has the same method name like <code>Socket</code>.
See also <code>public_send</code>.

   class Klass
     def hello(*args)
       "Hello " + args.join(' ')
     end
   end
   k = Klass.new
   k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"

Overloads:


1134
1135
1136
1137
1138
# File 'vm_eval.c', line 1134

VALUE
rb_f_send(int argc, VALUE *argv, VALUE recv)
{
    return send_internal_kw(argc, argv, recv, CALL_FCALL);
}

#==(other) ⇒ Boolean #equal?(other) ⇒ Boolean #eql?(other) ⇒ Boolean

Equality — At the Object level, #== returns true only if obj and other are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.

Unlike #==, the #equal? method should never be overridden by subclasses as it is used to determine object identity (that is, a.equal?(b) if and only if a is the same object as b):

obj = "a"
other = obj.dup

obj == other      #=> true
obj.equal? other  #=> false
obj.equal? obj    #=> true

The #eql? method returns true if obj and other refer to the same hash key. This is used by Hash to test members for equality. For any pair of objects where #eql? returns true, the #hash value of both objects must be equal. So any subclass that overrides #eql? should also override #hash appropriately.

For objects of class Object, #eql? is synonymous with #==. Subclasses normally continue this tradition by aliasing #eql? to their overridden #== method, but there are exceptions. Numeric types, for example, perform type conversion across #==, but not across #eql?, so:

1 == 1.0     #=> true
1.eql? 1.0   #=> false

Overloads:

  • #==(other) ⇒ Boolean

    Returns:

    • (Boolean)
  • #equal?(other) ⇒ Boolean

    Returns:

    • (Boolean)
  • #eql?(other) ⇒ Boolean

    Returns:

    • (Boolean)

234
235
236
237
238
239
# File 'object.c', line 234

MJIT_FUNC_EXPORTED VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
    if (obj1 == obj2) return Qtrue;
    return Qfalse;
}

#instance_eval(string[, filename [, lineno]]) ⇒ Object #instance_eval {|obj| ... } ⇒ Object

Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj's instance variables and private methods.

When instance_eval is given a block, obj is also passed in as the block's only argument.

When instance_eval is given a String, the optional second and third parameters supply a filename and starting line number that are used when reporting compilation errors.

class KlassWithSecret
  def initialize
    @secret = 99
  end
  private
  def the_secret
    "Ssssh! The secret is #{@secret}."
  end
end
k = KlassWithSecret.new
k.instance_eval { @secret }          #=> 99
k.instance_eval { the_secret }       #=> "Ssssh! The secret is 99."
k.instance_eval {|obj| obj == self } #=> true

Overloads:

  • #instance_eval(string[, filename [, lineno]]) ⇒ Object

    Returns:

  • #instance_eval {|obj| ... } ⇒ Object

    Yields:

    • (obj)

    Returns:


1924
1925
1926
1927
1928
1929
# File 'vm_eval.c', line 1924

static VALUE
rb_obj_instance_eval_internal(int argc, const VALUE *argv, VALUE self)
{
    VALUE klass = singleton_class_for_eval(self);
    return specific_eval(argc, argv, klass, self, RB_PASS_CALLED_KEYWORDS);
}

#instance_exec(arg...) {|var...| ... } ⇒ Object

Executes the given block within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj's instance variables. Arguments are passed as block parameters.

class KlassWithSecret
  def initialize
    @secret = 99
  end
end
k = KlassWithSecret.new
k.instance_exec(5) {|x| @secret+x }   #=> 104

Yields:

  • (var...)

Returns:


1956
1957
1958
1959
1960
1961
# File 'vm_eval.c', line 1956

static VALUE
rb_obj_instance_exec_internal(int argc, const VALUE *argv, VALUE self)
{
    VALUE klass = singleton_class_for_eval(self);
    return yield_under(klass, self, argc, argv, RB_PASS_CALLED_KEYWORDS);
}

#singleton_method_added(_y) ⇒ Object (private)

call-seq:

   singleton_method_added(symbol)

Invoked as a callback whenever a singleton method is added to the
receiver.

   module Chatty
     def Chatty.singleton_method_added(id)
       puts "Adding #{id.id2name}"
     end
     def self.one()     end
     def two()          end
     def Chatty.three() end
   end

<em>produces:</em>

   Adding singleton_method_added
   Adding one
   Adding three

1146
1147
1148
1149
1150
# File 'object.c', line 1146

static VALUE
rb_obj_dummy1(VALUE _x, VALUE _y)
{
    return rb_obj_dummy();
}

#singleton_method_removed(_y) ⇒ Object (private)

call-seq:

   singleton_method_removed(symbol)

Invoked as a callback whenever a singleton method is removed from
the receiver.

   module Chatty
     def Chatty.singleton_method_removed(id)
       puts "Removing #{id.id2name}"
     end
     def self.one()     end
     def two()          end
     def Chatty.three() end
     class << self
       remove_method :three
       remove_method :one
     end
   end

<em>produces:</em>

   Removing three
   Removing one

1146
1147
1148
1149
1150
# File 'object.c', line 1146

static VALUE
rb_obj_dummy1(VALUE _x, VALUE _y)
{
    return rb_obj_dummy();
}

#singleton_method_undefined(_y) ⇒ Object (private)

call-seq:

   singleton_method_undefined(symbol)

Invoked as a callback whenever a singleton method is undefined in
the receiver.

   module Chatty
     def Chatty.singleton_method_undefined(id)
       puts "Undefining #{id.id2name}"
     end
     def Chatty.one()   end
     class << self
        undef_method(:one)
     end
   end

<em>produces:</em>

   Undefining one

1146
1147
1148
1149
1150
# File 'object.c', line 1146

static VALUE
rb_obj_dummy1(VALUE _x, VALUE _y)
{
    return rb_obj_dummy();
}