PONYΞ»M2Modula-2
CodeCompared
for Python programmers

You already know Python.Now explore other languages.

Side-by-side, interactive cheatsheets for Python programmers
comparing Python to other languages. Every example runs live in your browser β€” no setup, no installation.

β–Ά Start with RubyBrowse comparisons ↓Explore the language map β†—

Choose your own path by reordering languages

Ruby⚑ Works Offline⚑ Offline

Python's closest peer and philosophical foil. Both are readable, dynamic, and expressive, but Ruby's blocks, open classes, and "there's more than one way" ethos give you a richer object model β€” the language that gave the world Rails and proved convention-over-configuration could be beautiful.

  • Blocks and closures β€” first-class behavior with do…end syntax; more powerful than Python's single-expression lambdas
  • Open classes β€” add methods to any class, even Integer or String, without subclassing or monkey-patching via modules
  • Everything is an object β€” integers, booleans, and nil all have methods; there's no primitive/object split
  • Convention over configuration β€” Rails structures your entire app for you; no Django settings sprawl
  • Symbols as lightweight identifiers β€” :name vs "name" β€” a distinction Python's str type doesn't make
GoPre-Alpha

Python's favorite upgrade path. When you've hit a performance wall or need concurrency without the GIL, Go delivers static types, native goroutines, and 10Γ— throughput β€” with a learning curve much shorter than Rust or C++.

  • Goroutines β€” thousands of concurrent tasks at ~2 KB each; Python threads are blocked by the GIL for CPU-bound work and asyncio requires async/await everywhere
  • Static typing β€” the compiler catches type mismatches before runtime, unlike Python's duck typing and optional type hints
  • 10–100Γ— faster for CPU-bound work β€” compiled to native code, no interpreter overhead, no GIL
  • Single binary deployment β€” no venv, no pip, no Python version to manage; ship one executable file
  • Error values instead of exceptions β€” every error is explicit in the function signature; no hidden propagation
  • Goroutines + channels replace both threading and asyncio with one unified model
JavaScriptAlpha⚑ Works Offline⚑ Offline

The language of the browser, JavaScript is the one runtime every Python web developer eventually meets on the front end.

  • Truthiness traps: empty [] and {} are truthy in JavaScript but falsy in Python
  • Two empty values β€” null and undefined β€” where Python has only None
  • === vs. ==: the strict equality you should reach for, and the coercing one you should avoid
  • Array methods (map, filter, reduce) in place of list comprehensions
  • Prototype-based classes with this instead of an explicit self
  • A built-in event loop: async/await with no explicit asyncio.run()
CPre-Alpha

The language CPython is written in. Every list, dict and str you use is a C struct with a refcount on the front β€” so C is less a foreign language than the floor underneath the one you already know.

  • Pointers are the references Python hides β€” & and * make explicit what a name binding already is
  • Manual malloc/free instead of reference counting, with leaks and use-after-free as the price
  • No list, dict or str β€” a string is a pointer to bytes ending in zero, and strlen is O(n)
  • Fixed-width integers that overflow, where Python's grow without limit
  • Return codes and errno instead of exceptions; nothing forces the caller to check
  • What a C extension and ctypes actually do, including releasing the GIL for real parallelism
KotlinPre-Alpha

Roughly what a Python developer wishes Java were β€” and then null becomes a type error. Inference, top-level functions, expressions instead of statements, data classes, and no ceremony to speak of. So this page is not about boilerplate: it is about what a type system buys once the boilerplate is gone.

  • String and String? are different types, and the compiler refuses the call your annotation only ever documented
  • data class is @dataclass with copy(), destructuring and generated equality β€” and == is structural while === is identity, the reverse of Python's naming
  • Extension functions are monkey-patching done safely: statically resolved, scoped by import, and unable to collide with anyone else's
  • when over a sealed type is checked for exhaustiveness at compile time, which is the one thing match cannot do
  • Coroutines have no await at the call site and no event loop to pass around, and structured concurrency cancels the children for you
  • Real parallelism, no GIL β€” and Gradle, honestly, in place of pip and an activated environment
RustPre-Alpha

Python's expressiveness, but with memory safety, concurrency without the GIL, and performance without a rewrite. Rust eliminates entire classes of bugs at compile time while keeping code readable.

  • No GIL β€” true parallelism out of the box; Rust threads share memory without a global lock, unlike Python's threading module
  • Ownership and borrowing replace garbage collection β€” zero-pause memory management with no runtime overhead
  • Option and Result make None and errors explicit in the type system β€” no more AttributeError: 'NoneType' object has no attribute at runtime
  • Types are checked at compile time β€” the class of bugs Python's type hints warn about, Rust refuses to compile
  • Pattern matching with exhaustive match β€” more powerful than Python's match, and the compiler enforces you handle every case
  • Fearless concurrency β€” the borrow checker prevents data races that Python's GIL only partially guards against
SwiftPre-Alpha

A struct is a copy, and that is the whole first hour. Python has nothing like value semantics β€” every name is a reference, which is exactly why def f(items=[]) misbehaves. Add optionals as a type rather than a value that can turn up anywhere, and most of the surprise on this page is accounted for.

  • A struct β€” and Array, Dictionary, Set, String β€” copies on assignment, so no aliasing, no defensive copy, and no mutable-default-argument bug
  • String and String? are different types; if let, guard let and ?? are the ceremony that buys the guarantee
  • Protocols want the shape declared where duck typing asks at the moment of use, and some against any is the distinction that trips people up
  • Reference counting in both β€” CPython counts too β€” except Swift has no cycle collector, so weak and unowned are your job
  • async/await is spelled the same and runs on a real thread pool: genuinely parallel, with actor isolation checked by the compiler
  • Strings count grapheme clusters, so "πŸ‘¨β€πŸ‘©β€πŸ‘§".count is 1 where Python counts code points and says 5
TypeScriptAlpha⚑ Works Offline⚑ Offline

Python's familiar syntax meets compile-time type safety. TypeScript catches whole classes of bugs before they run β€” the same errors that only surface at runtime in Python.

  • Type annotations that are actually enforced β€” TypeScript's type system catches mismatches at compile time, not at 3am in production
  • Union types and Optional-equivalent T | null β€” the same expressiveness as Python's type hints, but verified by the compiler
  • interface and structural typing β€” like Python's Protocol, but built into the language and checked everywhere
  • Generics with <T> β€” the same concept as Python's TypeVar, with cleaner syntax and broader tooling support
  • Template literals that do what f-strings do β€” `Hello, ${name}!` vs f"Hello, {name}!"
C#Pre-Alpha

The static language that meets you halfway. LINQ is the comprehension you already write, yield return is yield, and async/await is spelled exactly the same. What is genuinely new is that types are checked before the program exists, that a struct copies when you assign it, and that two threads really do run at once.

  • LINQ is comprehensions as a library: Where/Select/GroupBy/Aggregate, deferred exactly like a generator expression β€” but re-runnable, where a generator is spent after one pass
  • yield return compiles to the same kind of state machine yield does, so your generators translate almost line for line
  • Value types have no Python counterpart: assigning a struct, or reading one out of a list, hands you a copy β€” the correctness surprise that costs newcomers the most time
  • Type hints check nothing; C# types are checked before the program is built, and var means inferred, never anything
  • async/await looks identical and promises more: no GIL, so Tasks and AsParallel() use every core
  • string? marks what may be null and the compiler warns when you forget to check β€” plus ?., ?? and ??= for the null dance
  • Records give you @dataclass with value equality and with expressions built in, and switch expressions are a match the compiler checks for exhaustiveness
JavaPre-Alpha⚑ Works Offline⚑ Offline

Everything you defer to run time, decided before the program starts. A type hint is a comment Java turns into a contract: the wrong argument is a build failure rather than a TypeError at 3am, there is no top level to write a script in, and the compiler asks you to say what Python let you leave implicit β€” the element type, the exception, the interface.

  • Types are enforced, not annotated β€” List<String> changes what compiles, where list[str] changes nothing unless you separately run mypy
  • No top level and no script: every statement lives in a method, every method in a class, and the program starts at public static void main(String[] args)
  • Checked exceptions put the failure modes in the signature and make the compiler insist you handle or declare them β€” an idea Python has no counterpart for, and one Java itself argues about
  • Real operating-system threads with no interpreter lock, so shared-memory parallelism replaces multiprocessing β€” and every piece of shared mutable state becomes yours to guard
  • record is @dataclass(frozen=True) built into the language, and sealed interfaces plus switch patterns give match the exhaustiveness check it lacks
  • 🚨 What bites: == compares identity so strings need .equals, an int wraps silently at 2Β³ΒΉ where a Python integer just grows, a missing key returns null instead of raising KeyError, and there is no comprehension, no keyword argument and no REPL habit
C++Pre-Alpha

You are almost certainly here because the fast part has to stop being Python. NumPy, PyTorch, Polars and pandas' new engine are C++ libraries with a thin Python face, so the common path is not "Python developer changes languages" but "Python developer has to touch the extension module". Nearly every surprise waiting for you comes from one sentence: in Python a variable is a name bound to an object, and in C++ the variable is the object.

  • 🚨 Assignment copies. second = first duplicates the whole container instead of aliasing it, and you ask for Python's behavior with a single &. Everything about lifetimes downstream follows from this
  • RAII replaces with and finally β€” a destructor runs at the closing brace, even while an exception unwinds, so cleanup lives in the type instead of at every call site
  • std::optional is your None as a type, std::expected (C++23) is the value-or-error return, and std::format borrowed Python's own mini-language, so {:.2f} means what you expect
  • Templates are duck typing moved to compile time, and C++20 concepts are typing.Protocol with the compiler actually enforcing it
  • shared_ptr is CPython's reference count, made visible β€” the same mechanism you already live inside, opted into per object, with the same cycle problem and no cycle collector
  • 🚨 Integers have edges and division rounds the other way: -7 / 2 is -3, not -4, and signed overflow is undefined behavior rather than a big number
  • Real threads and no interpreter lock, which is the speedup you came for β€” and pybind11's gil_scoped_release is the one line that turns an extension from faster into parallel
MojoPre-Alpha

Python syntax you already know, plus the performance you've always wanted. Mojo extends Python's familiar syntax with strict typing, value semantics, and SIMD β€” letting you write Python-style code that compiles to metal.

  • def functions work exactly like Python's β€” mutable arguments, implicit typing, no ceremony
  • fn functions are strict and typed β€” declared argument mutability, explicit return types, zero runtime overhead
  • var declares a new variable; Mojo's type inference means you rarely need to spell the type out
  • struct types have value semantics β€” no garbage collector, no hidden allocations, fully predictable performance
  • SIMD vectors are a first-class type β€” write vectorized math in plain Mojo without intrinsics or NumPy
  • Full Python interoperability via Python.import_module() β€” call any Python library directly
PHPPre-Alpha⚑ Works Offline⚑ Offline

Two dynamic languages that both grew optional typing, and only one of them means it. def greet(name: str) accepts 42 and fails later, somewhere else; function greet(string $name) throws at the call, and declare(strict_types=1) stops the engine coercing on the way in. This is the rare page where your own tooling is the looser of the two.

  • Declared types are checked by the engine on every call, where a Python annotation is inert unless you separately run mypy
  • A fresh interpreter per request: nothing you put in a module-level dictionary survives, so every cache, session and pool lives in Redis or the database rather than in memory
  • One array does the work of list, dict and tuple β€” and it is copied on assignment, so the mutable-default-argument bug is unreachable
  • A function sees nothing outside itself: no enclosing scope, no module-level names, and a closure captures only what its use (...) clause names
  • No comprehensions β€” array_map and array_filter with callbacks, in the opposite order from each other, and array_filter keeps the keys
  • Modern PHP 8 has enums, match, readonly, constructor promotion, named arguments and ?->; Composer is the part of the ecosystem a Python developer envies
JuliaPre-Alpha

The scientific language that compiles to fast machine code, Julia gives Python developers NumPy-style array math and C-like speed without leaving a high-level, dynamic language.

  • 1-based indexing and inclusive ranges (1:3 is 1, 2, 3)
  • Broadcasting with the dot (sqrt.(values), numbers .* 2) instead of NumPy or loops
  • Multiple dispatch instead of classes β€” methods live outside the type and dispatch on every argument
  • ^ for exponentiation, and div(a, b) for floor division
  • Blocks close with end rather than indentation
  • Conditions must be a real Bool β€” no truthy/falsy values
RPre-Alpha

Where Python's data-science world meets the language built by statisticians. R is vector-first and data-frame-native β€” much of what NumPy and pandas add to Python is simply how R already works.

  • Everything is a vector β€” 42 is a length-1 vector and arithmetic is vectorized by default, so loops and comprehensions are rarely needed
  • 1-based indexing with inclusive ranges β€” x[1] is the first element and 1:5 is 1, 2, 3, 4, 5
  • <- for assignment and c() to build vectors, instead of = and list literals
  • data.frame is part of base R β€” the original inspiration for pandas, available with no import
  • NA for missing values, separate from NULL β€” first-class missingness rather than NaN/None
  • The apply family (sapply, lapply, vapply) in place of loops and method chains
RocPre-Alpha

Everything Python decides at run time, decided before the program starts. No None, no exceptions, no Any, no rebinding, no GIL and no garbage collector β€” and yet the parts you like survive: # comments, // floor division, match with guards and or-patterns, and interpolation that reads almost like an f-string.

  • There is no None. A function that might not find something says so in its return type, as a tag union, and the compiler will not let the caller skip the missing case β€” so the AttributeError on NoneType has no way to happen.
  • No exceptions at all. Failure is a returned Try value naming what went wrong, and ? marks every point a function can exit early β€” the opposite of a bare int() that raises invisibly.
  • Your type hints, actually enforced. Roc infers a type for every expression in the whole program, with no Any, no cast() and no way to write "trust me" β€” and a match that forgets a case is a compile error rather than a silent None.
  • A dict with fixed keys becomes a record, and a typo in a field name stops compiling instead of becoming a KeyError in production. Keys that really are data still get Dict.
  • No interpreter, no GIL, no collector. Memory is reference counted by the compiler β€” no cycle collector is needed, because immutability makes a cycle impossible β€” and a tail-recursive function runs in constant stack space rather than hitting a recursion limit.
  • Exact decimals without importing anything: Dec is an ordinary number type, so 0.1 + 0.2 really is 0.3 and you never reach for decimal.Decimal.
  • Be honest about the trade: no REPL, no notebooks, a package ecosystem measured in dozens, and a pre-1.0 standard library with no Str.replace and no JSON. Read it for the ideas, not for next quarter's project.
ForthPre-Alpha⚑ Works Offline⚑ Offline

Everything Python gives you for free, taken away β€” and one thing Python can never give you, added. Forth has no named variables, no types, no heap and no string library, so the work Python hides is done in the open. In exchange, a program can add new syntax to its own compiler while it runs.

  • No names for values: DUP, SWAP and OVER arrange the stack where Python would write a variable twice
  • A word takes its arguments from the stack and leaves its results there β€” returning three values needs no tuple at all
  • True is βˆ’1, not 1, and AND is bitwise, so 1 2 AND is false even though both numbers are truthy
  • Redefining a word does not change code already compiled against the old one β€” the opposite of Python's late binding, until you ask for DEFER
  • An IMMEDIATE word runs while the compiler runs, so UNLESS can be a real keyword rather than a function taking a lambda
  • Drive a Logo turtle with it: : SQUARE 4 0 DO 100 FORWARD 90 RIGHT LOOP ; draws on the page, the way Python's turtle module draws in a window
Drag cards to reorder Β· your order is saved locally