0
0
Rubyprogramming~15 mins

Self keyword behavior in Ruby - Deep Dive

Choose your learning style9 modes available
Overview - Self keyword behavior
What is it?
In Ruby, the keyword self refers to the current object that is executing the code. It helps identify the context in which methods or variables are accessed or defined. Self changes depending on where you use it, such as inside a class, module, or instance method. Understanding self is key to knowing how Ruby decides what code belongs to which object.
Why it matters
Without self, Ruby wouldn't know which object you mean when calling methods or accessing variables, especially when names overlap. This would make code confusing and error-prone, as Ruby needs a clear way to know the current context. Self helps organize code and supports object-oriented design by clearly linking behavior to objects.
Where it fits
Before learning self, you should understand Ruby basics like classes, objects, methods, and variables. After mastering self, you can explore advanced topics like metaprogramming, singleton methods, and class vs instance scopes.
Mental Model
Core Idea
Self is the current object that owns or runs the code at any moment.
Think of it like...
Imagine you are in a room and say 'I am here.' The word 'I' changes meaning depending on who is speaking. In Ruby, self is like 'I' — it always means the current speaker or object.
┌───────────────────────────────┐
│           self                │
│  (current object context)     │
├─────────────┬─────────────────┤
│ In instance │ In class/module │
│  methods    │  definitions    │
│  (object)   │  (class object) │
└─────────────┴─────────────────┘
Build-Up - 7 Steps
1
FoundationWhat is self in Ruby?
🤔
Concept: Introduce self as the current object context in Ruby code.
In Ruby, self is a special keyword that always points to the object that is currently executing the code. For example, inside an instance method, self refers to the instance of the class. Outside any method, self can refer to the main object or the class itself.
Result
You understand that self changes meaning depending on where you use it.
Knowing that self is not fixed but depends on context is the foundation for understanding Ruby's object model.
2
FoundationSelf inside instance methods
🤔
Concept: Show how self refers to the instance inside instance methods.
class Dog def initialize(name) @name = name end def speak "Woof! I am #{self.name}" end def name @name end end fido = Dog.new("Fido") puts fido.speak
Result
Woof! I am Fido
Inside instance methods, self is the specific object calling the method, so you can access its data and methods.
3
IntermediateSelf inside class definitions
🤔
Concept: Explain how self refers to the class object inside class definitions but outside instance methods.
class Cat puts self # => Cat def self.species "Feline" end end puts Cat.species
Result
Cat Feline
Inside the class body but outside instance methods, self is the class itself, allowing you to define class methods.
4
IntermediateUsing self to define class methods
🤔Before reading on: do you think 'def self.method' defines an instance method or a class method? Commit to your answer.
Concept: Show how prefixing method names with self defines class methods.
class Bird def self.fly "I can fly!" end end puts Bird.fly
Result
I can fly!
Understanding that self in method definitions controls whether the method belongs to the class or instances helps organize code clearly.
5
IntermediateSelf inside singleton methods
🤔Before reading on: do you think self inside a singleton method refers to the singleton object or the class? Commit to your answer.
Concept: Explain how self behaves inside singleton methods defined on individual objects.
str = "hello" def str.shout self.upcase + "!" end puts str.shout
Result
HELLO!
Knowing that self inside singleton methods refers to the specific object allows customizing behavior per object.
6
AdvancedChanging self with instance_eval
🤔Before reading on: do you think instance_eval changes self inside the block to the receiver or keeps it the same? Commit to your answer.
Concept: Show how instance_eval changes self temporarily to the receiver object inside a block.
class Person def initialize(name) @name = name end end p = Person.new("Alice") p.instance_eval do puts self # => p (Person object) puts @name # => Alice end
Result
Person object Alice
Understanding instance_eval's effect on self unlocks powerful metaprogramming techniques.
7
ExpertSelf and method lookup path surprises
🤔Before reading on: do you think self affects method lookup or only variable resolution? Commit to your answer.
Concept: Reveal how self influences which methods Ruby calls, especially with modules and inheritance.
module M def greet "Hello from M" end end class A include M def greet "Hello from A" end def call_greet self.greet end end class B < A end b = B.new puts b.call_greet
Result
Hello from A
Knowing that self determines method lookup helps avoid bugs when methods are overridden or mixed in.
Under the Hood
Ruby keeps track of self as a pointer to the current object context during code execution. When Ruby runs code, it sets self to the object owning the current method or block. This affects how Ruby resolves method calls and variable access. For example, calling a method without an explicit receiver uses self as the receiver. Changing self (e.g., with instance_eval) temporarily changes this pointer, altering method resolution and variable scope.
Why designed this way?
Ruby was designed to be fully object-oriented, where everything is an object. Using self as the current object context makes method calls and variable access consistent and flexible. It allows clear distinction between instance and class methods and supports metaprogramming by letting code change context dynamically. Alternatives like fixed global contexts would limit expressiveness and clarity.
┌───────────────────────────────┐
│          Ruby runtime          │
├─────────────┬─────────────────┤
│   Code runs │ self points to  │
│             │ current object  │
├─────────────┴─────────────────┤
│ Method call without receiver   │
│ uses self as receiver          │
├───────────────────────────────┤
│ instance_eval changes self     │
│ temporarily inside block       │
└───────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does self always refer to the same object throughout a class? Commit to yes or no.
Common Belief:Self always refers to the instance of the class inside the class definition.
Tap to reveal reality
Reality:Self refers to the class object itself inside the class body, but to instances inside instance methods.
Why it matters:Confusing this leads to defining methods in the wrong place, causing unexpected behavior or errors.
Quick: Does using self inside a method call always mean calling a class method? Commit to yes or no.
Common Belief:Using self.method inside any method calls a class method.
Tap to reveal reality
Reality:Using self.method inside an instance method calls another instance method on the same object, not a class method.
Why it matters:Misunderstanding this causes bugs when trying to call methods on the wrong level (class vs instance).
Quick: Does changing self with instance_eval affect variables outside the block? Commit to yes or no.
Common Belief:Changing self with instance_eval changes the entire program's self permanently.
Tap to reveal reality
Reality:instance_eval only changes self temporarily inside the block; outside, self returns to normal.
Why it matters:Assuming permanent change leads to confusing bugs and unpredictable code behavior.
Quick: Does self affect only method calls, not variable access? Commit to yes or no.
Common Belief:Self only matters for method calls, not for accessing instance variables.
Tap to reveal reality
Reality:Self determines the context for both method calls and instance variable access; instance variables belong to self.
Why it matters:Ignoring this causes confusion about where variables come from and why some variables are nil or inaccessible.
Expert Zone
1
Inside class << self blocks, self changes to the singleton class, enabling defining class-level methods and variables in a clean way.
2
Using self explicitly in setters avoids creating local variables instead of calling setter methods, preventing subtle bugs.
3
Metaprogramming methods like define_method capture self differently, affecting method visibility and scope in surprising ways.
When NOT to use
Avoid relying on self in deeply nested blocks or procs where context can be confusing; instead, use explicit receivers or local variables. For global or module-level code, prefer explicit module names to avoid ambiguity.
Production Patterns
In production Ruby code, self is used to define class methods, singleton methods, and to clarify method calls. Frameworks like Rails use self heavily in DSLs and metaprogramming to dynamically define behavior tied to models or controllers.
Connections
This keyword in JavaScript
Similar concept of current object context but with different binding rules.
Understanding Ruby's self clarifies how object context works in other languages, highlighting differences in dynamic vs lexical binding.
Object-oriented programming (OOP)
Self is a core part of OOP, representing the current object instance.
Grasping self deepens understanding of how objects encapsulate data and behavior in OOP.
Actor model in concurrent computing
Both use the idea of a current 'actor' or 'self' handling messages or actions.
Recognizing self as the current actor helps connect Ruby's object context to concurrency models where each actor manages its own state.
Common Pitfalls
#1Defining instance methods as class methods by accident.
Wrong approach:class Dog def self.bark "Woof" end def bark "Bark bark" end end Dog.bark # works Dog.new.bark # works Dog.bark # expecting instance bark but calls class bark
Correct approach:class Dog def bark "Bark bark" end end Dog.new.bark # works # Dog.bark # error: undefined method
Root cause:Confusing self inside method definitions leads to mixing class and instance methods.
#2Using self in setter methods incorrectly causing local variable creation.
Wrong approach:class Cat def name=(value) name = value # wrong: creates local variable end end
Correct approach:class Cat def name=(value) @name = value # correct: sets instance variable end end
Root cause:Not using @ or self leads Ruby to treat assignment as local variable creation.
#3Assuming self inside blocks always refers to the outer object.
Wrong approach:class Person def greet [1].each do puts self # might not be what you expect end end end
Correct approach:class Person def greet [1].each do puts self # still the instance, but beware of procs/lambdas end end end
Root cause:Misunderstanding how self behaves inside blocks and procs causes confusion about context.
Key Takeaways
Self in Ruby always points to the current object context where code runs, changing meaning based on location.
Inside instance methods, self is the object instance; inside class bodies, self is the class object itself.
Using self explicitly helps define class methods, singleton methods, and clarifies method calls.
Changing self temporarily with methods like instance_eval enables powerful metaprogramming but requires care.
Misunderstanding self leads to common bugs, so mastering it is essential for writing clear, correct Ruby code.