Question

Understanding Ruby's Double-Colon :: Operator

rubysyntaxoperators

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.

  • private methods cannot be called with an explicit receiver in normal use.
  • protected methods 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, and protected

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::User means “open the Admin folder, then find the User item inside it”.
  • Math::PI means “look inside the Math folder for PI”.

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.

Take Quiz

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

  1. Ruby defines the module Store.
  2. Inside Store, it defines a constant TAX_RATE with value 0.1.
  3. Inside Store, it defines a class Product.
  4. Store::Product.new means:
    • Find the constant Product inside Store
    • Treat it as a class
    • Create a new object from it
  5. The price_with_tax method is called with 100.
  6. Inside that method, Store::TAX_RATE means:
    • Find the constant TAX_RATE inside Store
    • Use its value, 0.1
  7. Ruby calculates 100 + (100 * 0.1).
  8. 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.

Take Quiz

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:

  • private helper 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

ConceptWhat it accessesTypical useAffects privacy?
::Constants, nested classes/modules, namespacesMath::PI, Admin::UserNo
.Methods on an objectuser.name, array.lengthYes, method visibility matters
::NameTop-level constant lookup::String, ::ArrayNo

:: 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

VisibilityWho can call it?Explicit receiver allowed?
publicAnyoneYes
privateOnly inside the defining class contextUsually no
protectedRelated objects of the same class hierarchyYes, 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.

Take Quiz

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
  • private and protected control 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.

Take Quiz

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

  1. Create a module named AppConfig with at least one constant.
  2. Create another module named Reports containing a class called Generator.
  3. Make Generator use AppConfig:: to read configuration.
  4. Instantiate the class using its full namespaced path.
  5. Include one private helper method inside the class to show that :: does not replace method visibility.
Take Quiz

Keep learning

Related questions

View more