Cross-Language Comparison

Learning Objectives

Compare core OOP mechanisms across C++, Java, C#, Python and TypeScript.

Know the language versions behind each statement.

Prerequisites: Modules 77–81.

Intuition and Definition

Versions assumed: C++23, Java 21, C# 12/.NET 8+, Python 3.10+, TypeScript 5.x on ES2022.

values (copy) by default references (class), values (struct) public/protected/private, friend + package-private + internal, file convention (_, __) compile-time modifiers + #private yes (+ virtual bases) single + mixins dynamic (everything) dynamic (prototype lookup) interface (+ default methods) interface (+ default members) ABCs, Protocols structural interface (erased) class attributes, @staticmethod constructors + init lists constructors, this()/super() constructors, primary ctors, initializers __new__ / __init__ constructor, super() first GC (+ AutoCloseable) GC + IDisposable ref counting + GC, context managers GC (+ using in newer runtimes) templates (instantiated), concepts erased, wildcards reified, in/out type hints only structural, erased RTTI only (static reflection coming) JS object introspection only exceptions, expected checked + unchecked exceptions (untyped) const, value types final, records readonly, init, records frozen dataclasses, tuples readonly, Object.freeze ==/<=>, std::hash Equals/GetHashCode, records reference equality only (no hook) threads, atomics, coroutines threads, virtual threads, CompletableFuture Task, async/await asyncio, threads (GIL) event loop, promises, workers

Why It Matters

Concepts transfer; mechanics don't. Knowing the differences prevents bugs when switching languages — e.g. expecting C++ value semantics in Java, Java-style virtual-by-default in C#, or run-time interfaces in TypeScript.

Syntax and Language Notes

The same small value type in four languages — each run on the build machine:

#include <iostream>
struct Point { int x, y; bool operator==(const Point&) const = default; };
int main() {
    Point a{1, 2}, b = a;     // b is a COPY
    b.x = 9;
    std::cout << "a.x=" << a.x << " equal(copy of a)=" << (Point{1, 2} == a) << "\n";
}
a.x=1 equal(copy of a)=1
var a = new PointClass { X = 1, Y = 2 };
var b = a;                 // b is the SAME object (reference)
b.X = 9;
Console.WriteLine($"class: a.X={a.X}");
var s = new PointStruct { X = 1, Y = 2 };
var t = s;                 // struct: a copy
t.X = 9;
Console.WriteLine($"struct: s.X={s.X}, records equal: {new PointRecord(1, 2) == new PointRecord(1, 2)}");

class PointClass { public int X; public int Y; }
struct PointStruct { public int X; public int Y; }
record PointRecord(int X, int Y);
class: a.X=9
struct: s.X=1, records equal: True
from dataclasses import dataclass
@dataclass
class Point:
    x: int
    y: int
a = Point(1, 2)
b = a                      # same object
b.x = 9
print(f"a.x={a.x}", "equal by value:", Point(1, 2) == Point(1, 2), "identical:", Point(1, 2) is Point(1, 2))
a.x=9 equal by value: True identical: False
class Point {
  x: number; y: number;
  constructor(x: number, y: number) { this.x = x; this.y = y; }
}
const a = new Point(1, 2);
const b = a;               // same object
b.x = 9;
const copy = { ...a };     // explicit shallow copy
copy.x = 1;
console.log(`a.x=${a.x}`, "== on equal objects:", new Point(1, 2) === new Point(1, 2), "copy.x:", copy.x);
a.x=9 == on equal objects: false copy.x: 1

Complete Example

The tables and the four programs above are the example: the same assignment b = a copies in C++ (and for C# structs) but aliases in Java, C#, Python and TypeScript classes; value equality is automatic for C++ defaulted ==, C# records and Python dataclasses, but not for TypeScript objects.

Step-by-Step Walkthrough

C++: b = a copies; changing b leaves a unchanged.

C#: the class version aliases (a.X becomes 9), the struct version copies, records compare by value.

Python: assignment aliases; @dataclass generates value equality, but identity (is) still differs.

TypeScript: assignment aliases; === compares references, so two equal-looking points are not equal; spreading makes a shallow copy.

Common Mistakes

Expecting copies where a language aliases (and vice versa).

Expecting virtual-by-default in C++/C# or non-virtual in Java.

Expecting run-time generics/interfaces in Java (erasure) or TypeScript (erased types).

Expecting deterministic destructors in GC languages.

Trade-offs and Alternatives

No language is "most OO". Choose by domain, ecosystem and team; apply the same design principles in each with the language's idioms.

Real-World Use

Polyglot systems are normal: C++ on the ECU, C# or Java in the back end, Python for test automation, TypeScript in the web dashboard — all sharing the same domain model concepts and message contracts.

Practice

Q1. (Easy) Which of the five languages have value semantics for user-defined class objects by default?

Answer: C++ (C# only for structs/record structs).

Q2. (Medium) Which languages erase generic type arguments at run time?

Answer: Java (erasure) and TypeScript (all types erased); Python's hints aren't enforced at run time either.

Q3. (Advanced) Why does new Point(1,2) === new Point(1,2) evaluate to false in TypeScript, and how would you compare values?

Answer: === compares object references. Write an equals method comparing fields, compare serialized forms carefully, or use a library — JavaScript has no operator-overloading hook for equality.

Interview Question

Q1. "You're moving a team from Java to C++. What OOP differences will cause bugs?"

Answer: Value semantics (copies and slicing instead of references), manual ownership and lifetimes (RAII, smart pointers instead of GC), non-virtual by default (missing virtual means no dispatch), virtual destructors, multiple inheritance, templates instead of erased generics, no reflection, exceptions with RAII instead of finally, and undefined behaviour for things Java checks at run time (array bounds, null dereference, data races).

Quick Quiz

Q1. Default dispatch in C#?

Answer: Non-virtual.

Q2. Which languages support user-defined operator overloading?

Answer: C++, C# (selected operators) and Python (dunder methods).

Q3. Which language resolves multiple inheritance with the C3 MRO?

Answer: Python.

Summary

Same concepts, different mechanics: copy vs alias, virtual defaults, generics models, lifetimes, reflection.

Related: Modules 77–81.