Comparison Operators in Programming

Table of Contents

A Complete Guide to Comparing Values


Table of Contents

  1. Introduction to Comparison Operators
  2. Equality Operators
  3. Relational Operators
  4. Type Comparison Operators
  5. Comparison in Different Languages
  6. Special Comparisons
  7. String Comparison
  8. Object Comparison
  9. Chaining Comparisons
  10. NaN and Null Comparisons
  11. Common Pitfalls
  12. Performance Considerations
  13. Best Practices
  14. Interview Questions

Introduction to Comparison Operators

Comparison operators are fundamental building blocks in programming that allow us to compare values and make decisions based on those comparisons. They return a boolean value (true or false) that determines the flow of our programs.

What Are Comparison Operators?

Comparison operators evaluate the relationship between two operands and return a boolean result. They are essential for:

  • Making decisions (if statements, loops)
  • Sorting and searching algorithms
  • Validating user input
  • Controlling program flow
// Basic comparison examples
let age = 18;
let isAdult = age >= 18;     // true
let canVote = age === 18;    // true
let isTeen = age < 20 && age > 12; // true

Types of Comparison Operators

CategoryOperatorsPurpose
Equality==, ===, !=, !==Check if values are equal
Relational>, <, >=, <=Compare numeric/string values
Typetypeof, instanceof, isCheck data types

Equality Operators

Equality operators determine if two values are equal. Different languages handle equality differently.

Loose Equality (==)

Loose equality performs type coercion before comparison.

// JavaScript - loose equality (==)
console.log(5 == "5");      // true (string converted to number)
console.log(0 == false);    // true (boolean converted to number)
console.log(null == undefined); // true
console.log("" == 0);       // true
console.log([] == false);   // true (complex rules!)
console.log({} == {});      // false (different references)
// PHP - loose equality (==)
var_dump(5 == "5");        // bool(true)
var_dump(0 == false);      // bool(true)
var_dump(null == false);   // bool(true) - careful!

Strict Equality (===)

Strict equality checks both value and type without coercion.

// JavaScript - strict equality (===)
console.log(5 === "5");     // false (different types)
console.log(0 === false);   // false (different types)
console.log(null === undefined); // false
console.log(5 === 5);       // true
console.log(NaN === NaN);   // false (NaN is not equal to itself)
# Python - no loose equality, only strict
print(5 == "5")     # False (no coercion)
print(5 == 5)       # True
print(5 == 5.0)     # True (numeric types considered equal)

Inequality Operators

// JavaScript
console.log(5 != "5");      // false (loose inequality)
console.log(5 !== "5");     // true (strict inequality)
console.log(5 != 6);        // true
# Python
print(5 != "5")     # True
print(5 != 5)       # False
print(5 != 5.0)     # False

Language Comparison Table

LanguageLoose EqualityStrict EqualityNotes
JavaScript=====Coercion rules can be complex
Python== onlyN/ANo type coercion
Java== for primitivesequals() for objectsDifferent approach
PHP=====Similar to JavaScript
C#==Equals()Type-safe
Ruby==eql?Different semantics

Relational Operators

Relational operators compare the relative order of values.

Greater Than and Less Than

// JavaScript
console.log(10 > 5);    // true
console.log(10 < 5);    // false
console.log(10 >= 10);  // true
console.log(10 <= 5);   // false
// With type coercion
console.log("10" > 5);  // true (string converted to number)
console.log("apple" > "banana");  // false (lexicographic comparison)
# Python
print(10 > 5)       # True
print(10 < 5)       # False
print(10 >= 10)     # True
print(10 <= 5)      # False
# Python raises TypeError for incompatible types
# print("10" > 5)  # TypeError!
// Java
int a = 10;
int b = 5;
System.out.println(a > b);   // true
System.out.println(a < b);   // false
// Strings use compareTo method
String s1 = "apple";
String s2 = "banana";
System.out.println(s1.compareTo(s2) > 0);  // false

Numeric Comparison Examples

// Edge cases
console.log(Infinity > 1000000);    // true
console.log(Infinity > Infinity);   // false
console.log(-Infinity < -1000000);  // true
console.log(NaN > 5);               // false
console.log(NaN < 5);               // false
console.log(NaN >= NaN);            // false
console.log(NaN <= NaN);            // false

Type Comparison Operators

typeof Operator

// JavaScript - typeof returns a string
console.log(typeof 42);           // "number"
console.log(typeof "Hello");      // "string"
console.log(typeof true);         // "boolean"
console.log(typeof undefined);    // "undefined"
console.log(typeof null);         // "object" (quirks!)
console.log(typeof {});           // "object"
console.log(typeof []);           // "object"
console.log(typeof function(){}); // "function"
# Python - type() returns type object
print(type(42))           # <class 'int'>
print(type("Hello"))      # <class 'str'>
print(type(True))         # <class 'bool'>
print(type(None))         # <class 'NoneType'>
print(type([]))           # <class 'list'>
print(type({}))           # <class 'dict'>

instanceof Operator

// JavaScript - checks prototype chain
class Animal {}
class Dog extends Animal {}
let dog = new Dog();
console.log(dog instanceof Dog);      // true
console.log(dog instanceof Animal);   // true
console.log(dog instanceof Object);   // true
console.log([] instanceof Array);     // true
console.log([] instanceof Object);    // true
// Java - instanceof operator
String text = "Hello";
System.out.println(text instanceof String);     // true
System.out.println(text instanceof Object);     // true
// With inheritance
class Animal {}
class Dog extends Animal {}
Dog dog = new Dog();
System.out.println(dog instanceof Dog);      // true
System.out.println(dog instanceof Animal);   // true

is and is not (Python)

# Python - identity comparison
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a is b)     # False (different objects)
print(a is c)     # True (same object)
print(a is not b) # True
# For singletons
print(None is None)        # True
print(True is True)        # True
print(False is False)      # True

Comparison in Different Languages

JavaScript Comparison

// JavaScript - comprehensive comparison
console.log(5 == "5");          // true
console.log(5 === "5");         // false
// Object comparison
let obj1 = { value: 5 };
let obj2 = { value: 5 };
console.log(obj1 == obj2);      // false (different references)
console.log(obj1 === obj2);     // false
// Array comparison
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
console.log(arr1 == arr2);      // false

Python Comparison

# Python - clean and predictable
print(5 == "5")         # False
print(5 == 5.0)         # True
print(5 is 5)           # True (small integers cached)
# Object comparison
class Person:
def __init__(self, name):
self.name = name
def __eq__(self, other):
if isinstance(other, Person):
return self.name == other.name
return False
p1 = Person("Alice")
p2 = Person("Alice")
print(p1 == p2)     # True (custom __eq__)
print(p1 is p2)     # False (different objects)

Java Comparison

// Java - primitives vs objects
int a = 5;
int b = 5;
System.out.println(a == b);     // true
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2);    // false (different references)
System.out.println(s1.equals(s2)); // true
// Integer caching
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2);   // true (cached)
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4);   // false (not cached)

C# Comparison

// C# - type-safe comparisons
int a = 5;
int b = 5;
Console.WriteLine(a == b);     // true
string s1 = "Hello";
string s2 = "Hello";
Console.WriteLine(s1 == s2);    // true (string interning)
Console.WriteLine(object.ReferenceEquals(s1, s2)); // true
// Custom equality
class Person
{
public string Name { get; set; }
public override bool Equals(object obj)
{
return obj is Person other && Name == other.Name;
}
}

PHP Comparison

// PHP - complex comparison rules
var_dump(5 == "5");          // bool(true)
var_dump(5 === "5");         // bool(false)
var_dump(0 == false);        // bool(true)
var_dump(0 === false);       // bool(false)
// String comparison
var_dump("10" > "2");        // bool(false) (lexicographic)
var_dump(10 > "2");          // bool(true) (numeric)

Special Comparisons

NaN Comparisons

NaN (Not a Number) behaves uniquely in comparisons.

// JavaScript
console.log(NaN == NaN);    // false
console.log(NaN === NaN);   // false
console.log(NaN > 0);       // false
console.log(NaN < 0);       // false
console.log(isNaN(NaN));    // true
console.log(Number.isNaN(NaN)); // true
// Number.isNaN is more reliable
console.log(Number.isNaN("abc"));  // false
console.log(isNaN("abc"));         // true (coerces to NaN)
# Python
import math
print(float('nan') == float('nan'))  # False
print(math.isnan(float('nan')))       # True

Null and Undefined Comparisons

// JavaScript
console.log(null == undefined);   // true
console.log(null === undefined);  // false
console.log(null == 0);           // false
console.log(null > 0);            // false
console.log(null < 0);            // false
console.log(null >= 0);           // true (weird!)
console.log(null <= 0);           // true (weird!)
# Python
print(None == None)     # True
print(None is None)     # True
# None compares only to None
print(None == 0)        # False

Infinity Comparisons

// JavaScript
console.log(Infinity > 1000000);     // true
console.log(Infinity > Infinity);    // false
console.log(Infinity >= Infinity);   // true
console.log(-Infinity < -1000000);   // true
console.log(1 / 0);                  // Infinity
console.log(-1 / 0);                 // -Infinity

String Comparison

Lexicographic Comparison

Strings are compared character by character based on their Unicode code points.

// JavaScript
console.log("apple" < "banana");    // true ('a' < 'b')
console.log("Apple" < "apple");     // true ('A' (65) < 'a' (97))
console.log("10" < "2");            // true ('1' < '2')
console.log("z" > "a");             // true
// Locale-aware comparison
console.log("ä".localeCompare("a")); // Usually 1 (ä > a)
# Python
print("apple" < "banana")     # True
print("Apple" < "apple")      # True
print("10" < "2")             # True (string comparison)
print(10 < 2)                 # False (numeric comparison)
# Case-insensitive comparison
print("APPLE".lower() == "apple".lower())  # True
// Java
String s1 = "apple";
String s2 = "banana";
System.out.println(s1.compareTo(s2) < 0);  // true
System.out.println(s1.equalsIgnoreCase("APPLE"));  // true

String Comparison Rules

// Unicode code point order
console.log("a" < "b");         // true
console.log("á" < "b");         // true (U+00E1 < U+0062? Actually 225 > 98, so false!)
console.log("z" < "ä");         // false (U+007A < U+00E4? 122 < 228, so true!)
// The actual Unicode order is based on code points, not alphabetical order

Object Comparison

Reference vs Value Comparison

// JavaScript - objects compared by reference
let obj1 = { name: "Alice" };
let obj2 = { name: "Alice" };
let obj3 = obj1;
console.log(obj1 === obj2);   // false (different references)
console.log(obj1 === obj3);   // true (same reference)
// Arrays are objects
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
console.log(arr1 === arr2);   // false
# Python - objects compared by identity by default
class Person:
def __init__(self, name):
self.name = name
p1 = Person("Alice")
p2 = Person("Alice")
p3 = p1
print(p1 is p2)      # False
print(p1 is p3)      # True
print(p1 == p2)      # False (unless __eq__ is defined)

Implementing Custom Equality

# Python - custom equality with __eq__
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if isinstance(other, Person):
return self.name == other.name and self.age == other.age
return False
def __hash__(self):
return hash((self.name, self.age))
p1 = Person("Alice", 30)
p2 = Person("Alice", 30)
print(p1 == p2)     # True
print(p1 is p2)     # False
// JavaScript - custom equality with method
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
equals(other) {
return other instanceof Person &&
this.name === other.name &&
this.age === other.age;
}
}
let p1 = new Person("Alice", 30);
let p2 = new Person("Alice", 30);
console.log(p1.equals(p2));  // true

Deep Comparison

// JavaScript - deep comparison function
function deepEqual(a, b) {
if (a === b) return true;
if (typeof a !== 'object' || typeof b !== 'object' || 
a === null || b === null) return false;
let keysA = Object.keys(a);
let keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
for (let key of keysA) {
if (!keysB.includes(key) || !deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { a: 1, b: { c: 2 } };
console.log(deepEqual(obj1, obj2));  // true

Chaining Comparisons

Chaining in Different Languages

# Python - supports comparison chaining
x = 5
print(1 < x < 10)      # True
print(1 < x > 3)       # True
print(1 < x < 3)       # False
# Multiple chaining
a = 5
b = 10
c = 15
print(a < b < c)       # True
print(a < b > c)       # False
// JavaScript - doesn't support chaining the same way
let x = 5;
console.log(1 < x && x < 10);  // true (must use &&)
console.log(1 < x < 10);       // true? Actually (1 < x) is true, true < 10? true becomes 1, so 1 < 10 is true - but not what you want!

Logical Operators for Chaining

// JavaScript - use && for chaining
let age = 25;
let isAdult = age >= 18 && age <= 65;  // true
// For multiple comparisons
let score = 85;
let grade = score >= 90 ? 'A' :
score >= 80 ? 'B' :
score >= 70 ? 'C' : 'F';
# Python - elegant chaining
age = 25
is_adult = 18 <= age <= 65  # True
# Range checking
temperature = 75
if 32 <= temperature <= 212:
print("Water is liquid")

NaN and Null Comparisons

NaN Comparisons

// JavaScript - NaN is not equal to anything
console.log(NaN === NaN);      // false
console.log(NaN == NaN);       // false
console.log(NaN > 0);          // false
console.log(NaN < 0);          // false
console.log(NaN >= NaN);       // false
console.log(NaN <= NaN);       // false
// Checking for NaN
console.log(isNaN(NaN));       // true
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("abc")); // false (doesn't coerce)
// Using Object.is (ES6)
console.log(Object.is(NaN, NaN));  // true
# Python
import math
print(float('nan') == float('nan'))  # False
print(math.isnan(float('nan')))      # True

Null and Undefined Comparisons

// JavaScript
console.log(null == undefined);   // true
console.log(null === undefined);  // false
console.log(null == 0);           // false
console.log(null > 0);            // false
console.log(null < 0);            // false
console.log(null >= 0);           // true (converts to 0)
console.log(null <= 0);           // true
// undefined with numbers
console.log(undefined == 0);      // false
console.log(undefined > 0);       // false
console.log(undefined < 0);       // false
console.log(undefined >= 0);      // false
console.log(undefined <= 0);      // false
# Python
print(None == 0)        # False
print(None is None)     # True
print(None == False)    # False

Common Pitfalls

1. Type Coercion in Loose Equality

// JavaScript - unexpected behavior
console.log([] == false);        // true
console.log([] == ![]);          // true
console.log("" == false);        // true
console.log("0" == false);       // true
console.log("0" == 0);           // true
console.log(false == "false");   // false
console.log({} == {});           // false
// Why [] == ![] is true:
// ![] = false
// [] == false
// [] == 0 (false converted to 0)
// "" == 0 ([] converted to "")
// 0 == 0 (true)

2. Floating Point Precision

// JavaScript
console.log(0.1 + 0.2 === 0.3);  // false
console.log(0.1 + 0.2);          // 0.30000000000000004
// Solution: use tolerance
const EPSILON = 0.000001;
console.log(Math.abs((0.1 + 0.2) - 0.3) < EPSILON);  // true
# Python
print(0.1 + 0.2 == 0.3)         # False
print(0.1 + 0.2)                # 0.30000000000000004
# Solution
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2') == Decimal('0.3'))  # True

3. String vs Number Comparisons

// JavaScript
console.log("10" > "2");        // false (lexicographic: '1' < '2')
console.log(10 > "2");          // true (numeric: 10 > 2)
console.log("10" > 2);          // true (converts to number)
# Python - TypeError, no automatic coercion
# print("10" > 2)  # TypeError!
print(int("10") > 2)  # True
print("10" > "2")    # False (lexicographic)

4. NaN Comparison Pitfall

// JavaScript
let result = Math.sqrt(-1);  // NaN
if (result === NaN) {        // Never true!
console.log("This never runs");
}
// Correct way
if (isNaN(result)) {
console.log("Result is NaN");
}

5. Null and 0 Comparison

// JavaScript
let value = null;
if (value == 0) {      // false
// Won't execute
}
if (value >= 0) {      // true! (null converted to 0)
// Will execute
}

Performance Considerations

Comparison Cost

// Primitive comparisons are fast
let a = 5;
let b = 10;
a === b;  // Fast
// Object comparisons require property checks
let obj1 = { x: 1, y: 2 };
let obj2 = { x: 1, y: 2 };
obj1 === obj2;  // Fast (reference comparison)
deepEqual(obj1, obj2);  // Slow (property iteration)
// Optimize deep comparisons
function optimizedDeepEqual(a, b) {
if (a === b) return true;
if (typeof a !== 'object' || typeof b !== 'object') return false;
let keysA = Object.keys(a);
let keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
// Use for loop instead of for...in for better performance
for (let i = 0; i < keysA.length; i++) {
let key = keysA[i];
if (!b.hasOwnProperty(key) || !deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}

Short-Circuit Optimization

// Order matters for performance
// Put cheaper comparisons first
if (isExpensiveCheck() && simpleCheck()) {  // Bad
}
if (simpleCheck() && isExpensiveCheck()) {  // Good
}

Best Practices

1. Use Strict Equality

// ❌ Bad
if (age == 18) { }
// ✅ Good
if (age === 18) { }

2. Explicit Type Conversion

// ❌ Bad
if (input == 5) { }
// ✅ Good
let num = Number(input);
if (num === 5) { }
# ❌ Bad
if input == 5:
pass
# ✅ Good
num = int(input)
if num == 5:
pass

3. Check for NaN Properly

// ❌ Bad
if (value === NaN) { }
// ✅ Good
if (Number.isNaN(value)) { }

4. Use Meaningful Variable Names

// ❌ Bad
if (a > b) { }
// ✅ Good
if (userAge >= LEGAL_DRINKING_AGE) { }

5. Handle Edge Cases

function compareNumbers(a, b) {
// Handle NaN
if (Number.isNaN(a) || Number.isNaN(b)) {
return false;
}
// Handle Infinity
if (a === Infinity && b === Infinity) return true;
if (a === -Infinity && b === -Infinity) return true;
return a === b;
}

6. Use Object.is for Special Cases

// Object.is handles NaN and -0 correctly
console.log(Object.is(NaN, NaN));     // true
console.log(Object.is(-0, +0));       // false
console.log(-0 === +0);               // true

Interview Questions

Q1: What's the difference between == and === in JavaScript?

// Answer: == performs type coercion, === does not
console.log(5 == "5");     // true (coerces string to number)
console.log(5 === "5");    // false (different types)
console.log(false == 0);   // true
console.log(false === 0);  // false
// Best practice: always use ===

Q2: What will this output?

console.log([] == false);      // true
console.log([] == ![]);        // true
console.log("" == false);      // true
console.log("" == 0);          // true
console.log("0" == false);     // true
console.log("0" == 0);         // true
console.log(false == "false"); // false

Q3: How would you compare two objects in JavaScript?

// Shallow comparison
function shallowEqual(obj1, obj2) {
if (obj1 === obj2) return true;
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (let key of keys1) {
if (obj1[key] !== obj2[key]) return false;
}
return true;
}
// Deep comparison
function deepEqual(obj1, obj2) {
if (obj1 === obj2) return true;
if (typeof obj1 !== 'object' || typeof obj2 !== 'object' ||
obj1 === null || obj2 === null) return false;
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (let key of keys1) {
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}

Q4: Why does NaN not equal itself?

// Answer: By IEEE 754 specification, NaN is not equal to anything
// This allows detection of invalid operations
let result = Math.sqrt(-1);  // NaN
if (result !== result) {     // true
console.log("NaN detected");
}
// Modern way
if (Number.isNaN(result)) {
console.log("NaN detected");
}

Q5: What's the output of this code?

console.log(1 < 2 < 3);    // true (1 < 2 = true, true < 3 = 1 < 3 = true)
console.log(3 > 2 > 1);    // false (3 > 2 = true, true > 1 = 1 > 1 = false)

Q6: Compare strings in different languages

// JavaScript
console.log("apple" < "banana");     // true
console.log("Apple" < "apple");      // true (Uppercase ASCII values are smaller)
// Python
// print("Apple" < "apple")  # True (same reason)

Q7: How to compare numbers with tolerance for floating point?

function almostEqual(a, b, epsilon = 0.000001) {
return Math.abs(a - b) < epsilon;
}
console.log(almostEqual(0.1 + 0.2, 0.3));  // true

Q8: What will this Python code output?

a = 256
b = 256
print(a is b)    # True (cached)
print(a == b)    # True
c = 257
d = 257
print(c is d)    # False (not cached)
print(c == d)    # True

Conclusion

Comparison operators are fundamental to programming logic and decision-making.

Key Takeaways

Operator TypeOperatorsBest Practice
Equality==, ===, !=, !==Use strict equality (===) in JavaScript, avoid loose equality
Relational>, <, >=, <=Be aware of type coercion; convert types explicitly
Typetypeof, instanceof, isUse appropriate type checking for your language

Best Practices Summary

  1. Use strict equality (===) over loose equality (==)
  2. Explicitly convert types before comparison
  3. Check for NaN using Number.isNaN() or isNaN()
  4. Be aware of floating point precision issues
  5. Understand chaining behavior in different languages
  6. Implement custom equality for objects when needed
  7. Consider performance in tight loops
  8. Handle edge cases (null, undefined, NaN, Infinity)

Quick Reference Card

// JavaScript best practices
// Equality
if (value === 5) { }           // Strict equality
if (value !== null) { }        // Strict inequality
// Type checking
if (typeof value === 'number') { }
if (Array.isArray(value)) { }
// NaN checking
if (Number.isNaN(value)) { }
// Floating point
if (Math.abs(a - b) < 1e-10) { }
// Null/undefined
if (value == null) { }          // Checks both null and undefined
// Chaining (use &&)
if (min <= value && value <= max) { }

Understanding comparison operators is essential for writing correct and predictable code. Master these concepts to become a more effective programmer!

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper