Question
In Ruby, what does the double-colon :: operator mean in expressions like Foo::Bar?
I found this definition:
The :: is a unary operator that allows: constants, instance methods and class methods defined within a class or module, to be accessed from anywhere outside the class or module.
What is the practical purpose of this operator, and how does it relate to visibility rules such as private and protected? If :: can access things from outside a class or module, does that mean it bypasses scope and exposes everything?
Short Answer
By the end of this page, you will understand what Ruby's :: operator is mainly used for, especially for namespaces and constants. You will also see that it does not magically bypass private or protected method visibility. In practice, :: is most commonly used to access constants inside modules and classes, such as Math::PI or Admin::User.
Concept
Ruby's double-colon operator :: is primarily used for constant lookup and namespacing.
In Ruby, classes and modules can contain constants, classes, and other modules. The :: operator lets you refer to something defined inside another class or module.
Example:
module Admin
class User
end
end
user_class = Admin::User
Here, User is defined inside the Admin namespace, so Admin::User means “the User constant inside Admin”.
Why this matters
Without namespaces, large Ruby programs would quickly run into naming conflicts.
For example, two different parts of an app might both want a class called User:
module Admin
class User
end
end
module CustomerArea
class User
end
end
Now Ruby can distinguish them:
Admin::User
CustomerArea::User
What :: is most commonly used for
- Accessing constants
- Referring to nested classes or modules
- Accessing top-level constants with
::Name
Example:
Math::PI
::String
Does :: bypass private and protected?
No. That is the key idea.
Method visibility rules still apply. Ruby does not let :: act as a universal bypass for private APIs.
The confusing definition you found is misleading if read too broadly. While Ruby syntax allows :: in some method-call-like contexts, in normal Ruby code it is mainly associated with constants and namespaces. It is not a tool for breaking encapsulation.
Private and protected are about methods
Ruby visibility keywords affect methods, not constants.
privatemethods cannot be called with an explicit receiver in normal use.protectedmethods are more restricted than public methods and are mainly callable between related objects.- Constants are a different concept entirely.
So this is valid constant access:
Math::PI
But visibility rules for methods still matter:
class Example
private
def secret
"hidden"
end
end
obj = Example.new
obj.secret # raises an error
Using :: does not turn a private method into a public one.
Important distinction
A lot of confusion comes from mixing up these two ideas:
- Constants and namespaces: accessed with
:: - Methods and visibility: controlled by
public,private, andprotected
These are related to object structure, but they solve different problems.
Mental Model
Think of a module or class as a folder, and constants/classes/modules inside it as files or subfolders.
Admin::Usermeans “open theAdminfolder, then find theUseritem inside it”.Math::PImeans “look inside theMathfolder forPI”.
Now think of private and protected as door locks on actions, not labels on folders.
- A constant is like a named item stored in a folder.
- A method is like an action you can ask an object to perform.
::helps you find the named item.- It does not give you a master key to locked actions.
So :: is more like an addressing tool than a security bypass.
Syntax and Examples
Core syntax
ModuleName::CONSTANT
ModuleName::ClassName
OuterModule::InnerModule::VALUE
::TopLevelConstant
Example 1: Accessing a constant
module AppConfig
VERSION = "1.0.0"
end
puts AppConfig::VERSION
Output:
1.0.0
VERSION is a constant stored inside the AppConfig module.
Example 2: Nested class
module Admin
class User
def role
"admin"
end
end
end
user = Admin::User.new
puts user.role
Output:
admin
Here, User is a class defined inside the Admin module.
Example 3: Top-level constant lookup
module Wrapper
String = "not the real String class"
def self.show
puts String
puts ::String
end
end
Wrapper.show
Output:
not the real String class
String
Inside Wrapper, String refers to the local constant first. ::String means “start from the top level”.
Example 4: Private method is still private
class SecretBox
private
def code
"1234"
end
end
box = SecretBox.new
box.code
This raises an error because code is private.
Using :: here is not the normal solution, because :: is not meant to expose private instance methods.
Step by Step Execution
Consider this example:
module Store
TAX_RATE = 0.1
class Product
def price_with_tax(price)
price + (price * Store::TAX_RATE)
end
end
end
product = Store::Product.new
puts product.price_with_tax(100)
Step by step
- Ruby defines the module
Store. - Inside
Store, it defines a constantTAX_RATEwith value0.1. - Inside
Store, it defines a classProduct. Store::Product.newmeans:- Find the constant
ProductinsideStore - Treat it as a class
- Create a new object from it
- Find the constant
- The
price_with_taxmethod is called with100. - Inside that method,
Store::TAX_RATEmeans:- Find the constant
TAX_RATEinsideStore - Use its value,
0.1
- Find the constant
- Ruby calculates
100 + (100 * 0.1). - The result is
110.0.
Output:
110.0
The important point is that :: is being used to find named constants inside a namespace.
Real World Use Cases
1. Organizing large applications
Ruby apps often group related classes into modules:
module Payments
class ChargeCustomer
end
class RefundPayment
end
end
Usage:
Payments::ChargeCustomer
Payments::RefundPayment
2. Avoiding naming collisions
Different parts of a system can reuse the same class names safely:
module Api
class Error
end
end
module Billing
class Error
end
end
3. Accessing framework or library constants
Ruby code often uses namespaced library classes:
Net::HTTP
JSON::ParserError
File::SEPARATOR
4. Configuration and shared values
Modules often hold constants for settings:
module Settings
API_URL = "https://example.com"
end
puts Settings::API_URL
5. Referring to nested classes in domain models
In larger systems, nested classes can clarify meaning:
module Reports
class Generator
end
end
This makes it obvious that Generator belongs to the reporting part of the app.
Real Codebase Usage
In real Ruby codebases, :: is most often used as a namespace separator.
Common patterns
Namespacing service objects
module Payments
class CreateInvoice
def call
# ...
end
end
end
Used as:
Payments::CreateInvoice.new.call
Grouping errors
module Auth
class Error < StandardError; end
class InvalidTokenError < Error; end
end
Used as:
raise Auth::InvalidTokenError, "Token expired"
Configuration modules
module AppConfig
TIMEOUT = 30
end
Explicit constant lookup for clarity
Developers sometimes write full names to avoid ambiguity:
::String
::Array
MyApp::User
How it fits with encapsulation
Real codebases do not use :: as a privacy workaround. Encapsulation is usually handled with:
privatehelper methods inside classes- small public APIs
- internal modules for grouping logic
- constants for configuration or shared values
- explicit namespacing to keep code readable
Related pattern: guard clauses
Although not directly about ::, namespaced classes often expose one public method and keep helper methods private:
module Payments
class CreateCharge
def call(amount)
return false if amount <= 0
process(amount)
end
private
def process(amount)
"Charged #{amount}"
end
end
end
Payments::CreateCharge is public as a constant path, but process is still a private method.
Common Mistakes
1. Thinking :: is mainly for private method access
This is the most common misunderstanding.
Incorrect idea
class Demo
private
def secret
"hidden"
end
end
d = Demo.new
# Expecting :: to bypass privacy
d::secret
Do not think of :: as a privacy bypass. Ruby visibility rules still matter, and this is not how :: is typically used.
2. Confusing constants with variables
Constants start with a capital letter in Ruby.
Broken example
module App
version = "1.0"
end
puts App::version
This does not work because version is a local variable, not a constant.
Correct version
module App
VERSION = "1.0"
end
puts App::VERSION
3. Forgetting that classes are constants too
In Ruby, class names are constants.
module Admin
class User
end
end
puts Admin::User
This works because User is a constant that refers to a class object.
4. Misunderstanding top-level lookup
If a local namespace has the same constant name as a global one, Ruby may resolve the local one first.
module Example
String = "custom"
puts String
end
If you want the real built-in String class, use:
::String
5. Expecting method visibility to affect constants
private and protected apply to methods, not constants.
class Demo
VALUE = 10
private
def helper
end
end
VALUE is a constant. helper is a method. They are different parts of Ruby's object model.
Comparisons
| Concept | What it accesses | Typical use | Affects privacy? |
|---|---|---|---|
:: | Constants, nested classes/modules, namespaces | Math::PI, Admin::User | No |
. | Methods on an object | user.name, array.length | Yes, method visibility matters |
::Name | Top-level constant lookup | ::String, ::Array | No |
:: vs .
Math::PI # constant lookup
user.name # method call
Use :: when referring to a constant path. Use . when calling methods.
private vs protected vs public
| Visibility | Who can call it? | Explicit receiver allowed? |
|---|---|---|
| public | Anyone | Yes |
| private | Only inside the defining class context | Usually no |
| protected | Related objects of the same class hierarchy | Yes, with restrictions |
These rules apply to methods, not constant lookup.
Namespace vs inheritance
- Namespace groups code:
Admin::User - Inheritance creates an is-a relationship:
class AdminUser < User
They solve different problems.
Cheat Sheet
Quick reference
Use :: for
- Accessing constants
- Accessing nested classes or modules
- Referring to top-level constants
Common syntax
ModuleName::CONSTANT
ModuleName::ClassName
Outer::Inner::VALUE
::String
Examples
Math::PI
Admin::User
Net::HTTP
::Array
Key rules
::is mainly for constant lookup- Class names and module names are constants in Ruby
privateandprotectedcontrol methods, not constants::does not exist to bypass encapsulation
Remember
user.name # method call
Admin::User # constant lookup
Edge case
If a constant name is shadowed inside a module, use top-level lookup:
::String
FAQ
Is :: the same as . in Ruby?
No. . is for calling methods. :: is mainly for constant and namespace lookup.
Can :: access private methods in Ruby?
In normal Ruby code, you should not think of :: as a way to bypass private methods. Method visibility rules still apply.
Why is Admin::User written with ::?
Because User is a constant defined inside the Admin module. :: tells Ruby to look inside that namespace.
What does ::String mean in Ruby?
It means the top-level String constant, which is useful if a local namespace also defines String.
Are classes and modules constants in Ruby?
Yes. That is why you can access them with ::.
Does private hide constants in Ruby?
No. private affects methods, not constants.
When should I use :: instead of .?
Use :: for constants and namespaces. Use . for method calls.
Mini Project
Description
Create a small Ruby program that models a namespaced application configuration and service class. This project demonstrates how :: is used to access nested classes and constants in a realistic way, without confusing it with method visibility.
Goal
Build a namespaced Ruby program that uses :: to access constants and nested classes correctly.
Requirements
- Create a module named
AppConfigwith at least one constant. - Create another module named
Reportscontaining a class calledGenerator. - Make
GeneratoruseAppConfig::to read configuration. - Instantiate the class using its full namespaced path.
- Include one private helper method inside the class to show that
::does not replace method visibility.
Keep learning
Related questions
Add a Default Value to an Existing Column in a Rails Migration
Learn how to add or change a default value on an existing database column using Rails Active Record migrations safely.
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.