Skip to content

00 — Start here

Level: 101 · read this first

This library is for someone who writes Python and is learning Ruby, someone who writes Ruby and wants to see what Python does with the same idea, and anyone who has been told "everything is an object" or "a block is not a closure" and would rather watch it happen than take it on trust. Every page asks one question of both languages and prints both answers.

What it assumes

That you can read a short program in at least one of the two languages. Nothing else: a page that needs an idea from another page links it, and a page that needs an idea about text, encodings or regular expressions links the Ruby text library ↗, which owns those subjects.

How to read a page

Each has the same shape: a one-line claim, the idea in prose, an output block from a Ruby program in that page's examples/ folder, a reading of that output, then Compared with Python — the same question put to Python by a second program, with its output beside the first — then an exercise with a solution you can unfold, and links. The output blocks are generated, never typed: if a page shows a value, Ruby 4.0 or Python 3 printed it, on Ubuntu and on macOS, and the build fails the day it stops.

Two programs per page is the point. A comparison you remember is a claim; a comparison you can run is a measurement, and the two languages are close enough that memory gets it wrong more often than you would think — which of them rounds 2.5 up, which one leaks a loop variable, which one lets you index past the end of an array.

The eight to read first

  1. nil, false and truthiness — the first thing a Python programmer gets wrong in Ruby: 0 and "" are true.
  2. Blocks are not objects — the construct Ruby has and Python does not, and what yield actually does.
  3. Default arguments are evaluated on each call — the mutable-default trap, present in one language and absent in the other.
  4. Hashes and default values — nil instead of KeyError, and the shared-default trap both languages have.
  5. private means no receiver — visibility that is enforced, against visibility that is a naming convention.
  6. StandardError is the default — what a bare rescue catches, and what a bare except: catches.
  7. case/in pattern matching — the two languages added the same feature in the same year with different spellings.
  8. Gotchas for Python programmers — every trap on one page, one measured line each, and its mirror image for the other direction.

Then go by chapter, or by the crosswalk, which puts every idea in one table with its Ruby and Python spellings, or by Topics A–Z.

Where the two languages agree

More than either community says. Both are dynamically typed, garbage-collected, object-based languages with duck typing, first-class functions, ordered hashes, unbounded integers, IEEE floats, generators, a global interpreter lock and a match statement. Assignment shares objects in both (Variables are references); integer division floors toward negative infinity in both, and % takes the sign of the divisor in both (Integer division floors); and/or return an operand rather than a boolean in both (and/or precedence); a for loop leaks its variable in both (for loops do not scope); containers print their elements with the programmer-facing form in both (to_s, inspect and p).

Where they differ, and which side surprises whom

Ruby will surprise a Python programmer with:

Python will surprise a Ruby programmer with:

The pattern: Ruby has two spellings where Python has one — lambda and proc, && and and, == and eql?, dup and clone — and the second spelling is where a Python programmer's model breaks. Python has two types where Ruby has one — str and bytes, list and tuple, set and frozenset — and the second type is where a Ruby programmer's model breaks. The crosswalk has a row for each pair.

The advanced half

Chapters 07 to 12 are where the designs diverge most: the object model (singleton classes, allocate, refinements), metaprogramming (define_method, method_missing, hooks, a DSL), under the hood (Binding, TracePoint, the garbage collector, the bytecode, the JITs) and concurrency (threads under the GVL, fibers, Ractors, processes). Each of those pages still carries a Python twin, because __init_subclass__, __getattr__, sys.settrace, dis and multiprocessing are the nearest Python has, and seeing exactly how near is the lesson.