ruby/ruby
Core classes
The implementations of Ruby's built-in types — String, Array, Hash, Integer, Float, Symbol, Proc, Method, Range, Regexp, Time, Struct, and so on. Most are split between a C file (memory layout, performance-critical operations) and an optional Ruby file (higher-level methods compiled into the binary).
Pages in this section
| Page | Covered classes |
|---|---|
| string-and-symbol.md | String, Symbol, mutable vs frozen strings |
| array-and-hash.md | Array, Hash, the st hash table, Set |
| numerics.md | Integer, Float, Bignum, Rational, Complex |
| proc-and-method.md | Proc, Lambda, Method, UnboundMethod, Binding |
For IO and File see systems/io.md. For Regexp see systems/regexp.md. For Module/Class/object internals see systems/vm.md and reference/data-models.md.
How a core class is structured
Most core classes follow a consistent pattern:
- C struct in
include/ruby/internal/core/: memory layout (RString,RArray,RHash, etc.). - C source in the repo root (
string.c,array.c,hash.c): allocation, mutation, performance-critical methods. - Optional Ruby source at the same name (
array.rb,hash.rb, etc.): higher-level methods that benefit from being expressed in Ruby. Compiled into the binary bytool/mk_builtin_loader.rb. - Init function (
Init_String,Init_Array,Init_Hash): registers methods withrb_define_method. Called frominits.c::rb_call_inits.
The Ruby-level files use a Primitive.foo syntax to call into C primitives. Example from array.rb:
class Array
def each_index
Primitive.attr! :inline_block
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)' unless block_given?
i = 0
while i < length
yield i
i += 1
end
self
end
endPrimitive.cexpr! and Primitive.attr! are recognised by tool/mk_builtin_loader.rb and lowered to direct C calls or attribute flags.
Why split between C and Ruby?
Historically, every method was C. Over time, many were rewritten in Ruby because:
- Ruby is easier to maintain than C.
- The compiler (and JITs) can optimise Ruby method bodies just as well as inline C, given enough type information.
- Errors and backtraces are cleaner when the body is Ruby.
The split is a judgement call per method. Anything that needs raw memory access (e.g., Array#sort, Hash#each) stays in C; control-flow-heavy methods that just orchestrate other methods (e.g., Array#each_index, Array#combination) move to Ruby.
Special-constant types
Several "core" types are not heap objects at all — they're encoded directly in the VALUE bits:
| Type | Encoding |
|---|---|
Fixnum |
low bit set; the integer is in the upper 63 bits |
Float |
(some platforms) low 2 bits = 0b10; mantissa in the upper bits |
Symbol |
low bits = SPECIAL_CONST_TAG_SYM for short symbols, otherwise heap |
nil |
Qnil (one-byte sentinel) |
false |
Qfalse |
true |
Qtrue |
Method dispatch on these types still finds methods through the class hierarchy (Integer, Float, Symbol, NilClass, FalseClass, TrueClass); the VM has fast paths to avoid actually allocating an object.
See reference/data-models.md for the bit-level details.
Class hierarchy
BasicObject
└── Object
├── Numeric
│ ├── Integer (Fixnum, Bignum)
│ ├── Float
│ ├── Rational
│ └── Complex
├── String (also includes Symbol kind-of)
├── Symbol
├── Array
├── Hash
├── Range
├── Regexp
├── Proc
├── Method / UnboundMethod
├── Struct (and Data, Set in newer versions)
├── Time
├── IO (parent of File, Socket, ...)
├── Thread / Fiber / Ractor / Mutex / Queue / Monitor
├── Exception (with StandardError, RuntimeError, ... subtree)
└── Module
└── ClassThe full layout is built in inits.c::rb_call_inits and the per-class Init_* functions.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.