Operators
How different programming languages handle arithmetic, comparison, logical, and overloadable operators.
JavaScript
Standard arithmetic, comparison (including loose == and strict ===), and
logical operators (&&, ||, ?? for nullish coalescing). Supports
optional chaining (?.) and spread/rest syntax. No operator overloading;
typeof/instanceof cover runtime type checks.
Python
Arithmetic includes floor division (//) and exponentiation (**);
comparisons can be chained (a < b < c). Logical operators are the keywords
and/or/not rather than symbols. Operator overloading is supported via
dunder methods (__add__, __eq__, etc.), and the walrus operator (:=)
allows assignment within expressions.
TypeScript
Runtime operators are identical to JavaScript’s, since TypeScript compiles
away its type layer. Adds type-level operators such as keyof, extends,
union (|) and intersection (&), plus the non-null assertion (!). No
operator overloading at runtime.
Java
Conventional operator set with no overloading. Ternary (?:) is available,
integer division truncates, and instanceof supports pattern matching in
newer versions to bind the checked type directly.
C#
Allows operator overloading via static operator methods, and provides
null-conditional (?.) and null-coalescing (??, ??=) operators.
Pattern-matching operators (is, relational patterns) extend conditional
logic beyond simple comparisons.
C++
Extends C’s operator set with extensive overloading support (operator+,
operator<<, etc.), enabling custom types to behave like built-ins. Also
adds the three-way comparison (“spaceship”) operator <=> for concise
ordering logic.
C
Covers arithmetic, bitwise, and logical operators plus pointer arithmetic and the comma operator. No overloading, and implicit type conversions between numeric types can be a common source of subtle bugs.
PHP
Standard arithmetic and comparison operators, including both loose (==)
and strict (===) equality, plus the spaceship (<=>) and null-coalescing
(??, ??=) operators. No user-level operator overloading in core PHP.
Go
Deliberately minimal: arithmetic, comparison, logical (&&, ||), and
bitwise operators, all short-circuiting where relevant. No operator
overloading, no ternary operator, and increment/decrement (++/--) are
statements rather than expressions.
Rust
Full arithmetic/logical/bitwise set, with operator overloading achieved
through traits like Add and Sub. No implicit numeric conversions, integer
overflow is checked in debug builds, and there’s no ternary — if is used
as an expression instead.
Kotlin
Operator overloading works through naming conventions (defining functions
like plus() marked operator). Notable extras include infix functions,
the Elvis operator (?:), safe-call (?.), and range operators (..,
..<). No dedicated ternary; if doubles as an expression.
Ruby
Almost every operator is sugar for a method call, so classes can overload
+, ==, <=>, and others by defining the corresponding method. Includes
the spaceship operator (<=>) for comparisons and safe navigation (&.)
for nil-safe calls.
Dart
Standard arithmetic, comparison, and logical operators, plus null-aware
ones like ??, ??=, and ?. for working with nullable types. Supports
operator overloading by defining methods such as operator+ on a class.
Swift
Supports operator overloading and even custom operator definitions.
Provides nil-coalescing (??), inclusive/half-open ranges (..., ..<),
and overflow-safe variants (&+, &-) for wraparound arithmetic.
Increment/decrement operators were removed from the language.
Perl
Distinguishes numeric operators (==, !=, <) from separate string
operators (eq, ne, lt); arithmetic includes exponentiation (**), and
the ternary (?:) operator is supported. No user-definable operator
overloading without the overload pragma.
Elixir
Arithmetic, comparison, and logical operators, with strict boolean versions
(and/or/not, requiring booleans) alongside truthy versions (&&,
||, !). The pipe operator (|>) threads a value through a sequence of
calls, and = is a match operator rather than plain assignment.
Scala
Nearly every operator is really a method call under the syntax sugar —
a + b desugars to a.+(b) — so custom types get operator-like syntax
simply by defining methods named +, ==, and so on. Pattern matching via
match/case stands in for a traditional switch statement.
Clojure
Arithmetic, comparison, and logical operations are ordinary prefix functions
((+ a b), (= a b), (and a b)) rather than infix operators, so there’s
no operator overloading in the conventional sense — polymorphism instead
comes through protocols and multimethods.
Haskell
Arithmetic and comparison operators (+, ==, <) are just infix
functions defined per typeclass (Num, Eq, Ord), so any type can
support them by implementing the right instance. Custom operators can be
defined freely, and the function composition (.) and application ($)
operators are used pervasively.