3  Class Syntax

I’ll provide you with a comprehensive comparison of class syntax across TypeScript, csharp, and Python. Let’s explore each aspect systematically with code examples and diagrams.

3.1 Basic Class Structure & Initialization

class Person {
    // Instance properties
    public name: string;
    private age: number;
    protected id: string;
    
    // Class (static) property
    static species: string = "Homo sapiens";
    
    // Constructor
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
        this.id = this.generateId();
    }
    
    private generateId(): string {
        return Math.random().toString();
    }
}

// Instantiation
const person = new Person("Alice", 30);
public class Person
{
    // Instance properties (with auto-properties)
    public string Name { get; set; }
    private int age;
    protected string Id { get; set; }
    
    // Class (static) property
    public static string Species { get; set; } = "Homo sapiens";
    
    // Constructor
    public Person(string name, int age)
    {
        Name = name;
        this.age = age;
        Id = GenerateId();
    }
    
    private string GenerateId()
    {
        return Guid.NewGuid().ToString();
    }
}

// Instantiation
var person = new Person("Alice", 30);
class Person:
    # Class variable
    species = "Homo sapiens"
    
    def __init__(self, name, age):
        # Instance variables
        self.name = name        # Public
        self._id = self._generate_id()  # Protected (convention)
        self.__age = age        # Private (name mangling)
    
    def _generate_id(self):
        import uuid
        return str(uuid.uuid4())

# Instantiation
person = Person("Alice", 30)

3.1.1 Multiple Constructor

Different languages handle multiple constructors differently. Here’s how to create objects with various initialization patterns:

class Employee {
    public name: string;
    public age: number;
    public department: string;

    // TypeScript doesn't support multiple constructors
    // Use optional parameters and overloading signatures
    constructor(name: string);
    constructor(name: string, age: number);
    constructor(name: string, age: number, department: string);
    constructor(name: string, age?: number, department?: string) {
        this.name = name;
        this.age = age ?? 0;
        this.department = department ?? "General";
    }

    // Static factory methods as an alternative
    static createIntern(name: string): Employee {
        return new Employee(name, 20, "Intern");
    }

    static createFromJson(json: string): Employee {
        const data = JSON.parse(json);
        return new Employee(data.name, data.age, data.department);
    }
}

// Usage
const emp1 = new Employee("Alice");
const emp2 = new Employee("Bob", 25);
const emp3 = new Employee("Charlie", 30, "Engineering");
const intern = Employee.createIntern("David");
const fromJson = Employee.createFromJson('{"name":"Eve","age":28,"department":"HR"}');
public class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Department { get; set; }

    // Default constructor
    public Employee() : this("Unknown", 0, "General")
    {
    }

    // Constructor with name only
    public Employee(string name) : this(name, 0, "General")
    {
    }

    // Constructor with name and age
    public Employee(string name, int age) : this(name, age, "General")
    {
    }

    // Full constructor
    public Employee(string name, int age, string department)
    {
        Name = name;
        Age = age;
        Department = department;
    }

    // Copy constructor
    public Employee(Employee other) : this(other.Name, other.Age, other.Department)
    {
    }

    // Static factory method
    public static Employee CreateIntern(string name)
    {
        return new Employee(name, 20, "Intern");
    }

    // Constructor with object initializer (alternative pattern)
    public static Employee CreateFromDictionary(Dictionary<string, object> data)
    {
        return new Employee
        {
            Name = data["name"].ToString(),
            Age = Convert.ToInt32(data["age"]),
            Department = data["department"].ToString()
        };
    }
}

// Usage
var emp1 = new Employee();
var emp2 = new Employee("Alice");
var emp3 = new Employee("Bob", 25);
var emp4 = new Employee("Charlie", 30, "Engineering");
var emp5 = new Employee(emp4);  // Copy constructor
var intern = Employee.CreateIntern("David");
class Employee:
    # Primary constructor
    def __init__(self, name="Unknown", age=0, department="General"):
        self.name = name
        self.age = age
        self.department = department

    # Alternative constructor using @classmethod
    @classmethod
    def create_intern(cls, name):
        """Create an intern with default settings"""
        return cls(name, 20, "Intern")

    @classmethod
    def from_dict(cls, data):
        """Create from dictionary"""
        return cls(data['name'], data['age'], data['department'])

    @classmethod
    def from_string(cls, employee_str):
        """Create from formatted string"""
        name, age, dept = employee_str.split('-')
        return cls(name, int(age), dept)

    @classmethod
    def copy_from(cls, other):
        """Copy constructor"""
        return cls(other.name, other.age, other.department)

    # Using *args and **kwargs for flexible initialization
    @classmethod
    def create_flexible(cls, *args, **kwargs):
        """Flexible factory method"""
        if len(args) == 1:
            return cls(args[0])  # Name only
        elif len(args) == 2:
            return cls(args[0], args[1])  # Name and age
        elif kwargs:
            return cls(**kwargs)  # Named arguments
        return cls()  # Default

# Usage
emp1 = Employee()
emp2 = Employee("Alice")
emp3 = Employee("Bob", 25)
emp4 = Employee("Charlie", 30, "Engineering")
emp5 = Employee.create_intern("David")
emp6 = Employee.from_dict({'name': 'Eve', 'age': 28, 'department': 'HR'})
emp7 = Employee.from_string("Frank-35-Finance")
emp8 = Employee.copy_from(emp4)
emp9 = Employee.create_flexible("Grace", department="Marketing")

3.1.2 Constructor Patterns Summary

Pattern TypeScript C# Python
Multiple Constructors Constructor overloading signatures True multiple constructors Default parameters + @classmethod
Optional Parameters param?: type Optional parameters or overloads Default values in __init__
Factory Methods Static methods Static methods @classmethod decorators
Copy Constructor Clone method or factory Copy constructor @classmethod with instance param
Named Constructors Static factory methods Static methods @classmethod with descriptive names
Builder Pattern Method chaining Fluent interface Method chaining or separate builder

3.2 Instance vs Class Members

Here’s a visual representation:

┌─────────────────────────────────────┐
│            CLASS                     │
│  ┌─────────────────────────────┐    │
│  │   Static/Class Members      │    │
│  │   - Shared by all instances │    │
│  └─────────────────────────────┘    │
│                                      │
│  ┌──────────┐  ┌──────────┐        │
│  │Instance 1│  │Instance 2│  ...    │
│  │ - name   │  │ - name   │        │
│  │ - age    │  │ - age    │        │
│  └──────────┘  └──────────┘        │
└─────────────────────────────────────┘
class Counter {
    // Instance property
    private count: number = 0;
    
    // Static property
    static totalCounters: number = 0;
    
    constructor() {
        Counter.totalCounters++;
    }
    
    // Instance method
    increment(): void {
        this.count++;
    }
    
    // Static method
    static getTotalCounters(): number {
        return Counter.totalCounters;
    }
}
public class Counter
{
    // Instance field
    private int count = 0;
    
    // Static field
    private static int totalCounters = 0;
    
    // Instance property
    public int Count => count;
    
    // Static property
    public static int TotalCounters => totalCounters;
    
    public Counter()
    {
        totalCounters++;
    }
    
    // Instance method
    public void Increment()
    {
        count++;
    }
    
    // Static method
    public static void ResetTotal()
    {
        totalCounters = 0;
    }
}
class Counter:
    # Class variable
    total_counters = 0
    
    def __init__(self):
        # Instance variable
        self.count = 0
        Counter.total_counters += 1
    
    # Instance method
    def increment(self):
        self.count += 1
    
    # Class method
    @classmethod
    def get_total_counters(cls):
        return cls.total_counters
    
    # Static method (no access to cls or self)
    @staticmethod
    def validate_count(value):
        return value >= 0

3.3 Access Modifiers Comparison

Language Public Private Protected Package/Internal
TypeScript public (default for members) private protected -
csharp public private (default) protected internal
Python name __name (name mangling) _name (convention) -
class BankAccount {
    public accountHolder: string;
    private balance: number;
    protected accountNumber: string;
    
    constructor(holder: string, initial: number) {
        this.accountHolder = holder;
        this.balance = initial;
        this.accountNumber = this.generateAccountNumber();
    }
    
    protected generateAccountNumber(): string {
        return "ACC" + Date.now();
    }
    
    public getBalance(): number {
        return this.balance;
    }
}
public class BankAccount
{
    public string AccountHolder { get; set; }
    private decimal balance;
    protected string AccountNumber { get; set; }
    internal string BranchCode { get; set; }  // Accessible within assembly
    
    public BankAccount(string holder, decimal initial)
    {
        AccountHolder = holder;
        balance = initial;
        AccountNumber = GenerateAccountNumber();
    }
    
    protected virtual string GenerateAccountNumber()
    {
        return "ACC" + DateTime.Now.Ticks;
    }
    
    public decimal GetBalance()
    {
        return balance;
    }
}
class BankAccount:
    def __init__(self, holder, initial):
        self.account_holder = holder      # Public
        self.__balance = initial          # Private (name mangled)
        self._account_number = self._generate_account_number()  # Protected
    
    def _generate_account_number(self):  # Protected method
        import time
        return f"ACC{int(time.time())}"
    
    def get_balance(self):  # Public method
        return self.__balance
    
    def __validate(self):  # Private method
        return self.__balance >= 0

3.4 Getters and Setters

Getters and setters (also called accessors and mutators) provide controlled access to private properties with validation and computed values.

┌──────────────────────────────────┐
│         Class                     │
│  ┌────────────────────────────┐  │
│  │  Private Field: _value     │  │
│  └────────────────────────────┘  │
│         ▲              ▲          │
│         │              │          │
│    ┌────┴────┐    ┌───┴────┐    │
│    │ Getter  │    │ Setter │    │
│    │ (read)  │    │ (write)│    │
│    └────┬────┘    └───┬────┘    │
│         │              │          │
│         └──────┬───────┘          │
│                │                   │
│         Public Interface          │
└────────────────┼───────────────────┘
                 │
           External Access
class Temperature {
    private _celsius: number = 0;

    // Getter
    get celsius(): number {
        return this._celsius;
    }

    // Setter with validation
    set celsius(value: number) {
        if (value < -273.15) {
            throw new Error("Temperature below absolute zero!");
        }
        this._celsius = value;
    }

    // Computed property (getter only)
    get fahrenheit(): number {
        return (this._celsius * 9/5) + 32;
    }

    set fahrenheit(value: number) {
        this.celsius = (value - 32) * 5/9;
    }
}

// Usage
const temp = new Temperature();
temp.celsius = 25;           // Calls setter
console.log(temp.celsius);   // Calls getter: 25
console.log(temp.fahrenheit);// Calls getter: 77
temp.fahrenheit = 68;        // Calls setter
console.log(temp.celsius);   // 20
public class Temperature
{
    private double _celsius = 0;

    // Full property with backing field
    public double Celsius
    {
        get { return _celsius; }
        set
        {
            if (value < -273.15)
                throw new ArgumentException("Temperature below absolute zero!");
            _celsius = value;
        }
    }

    // Auto-property (simplified)
    public string Unit { get; set; } = "Celsius";

    // Computed property (expression-bodied)
    public double Fahrenheit
    {
        get => (_celsius * 9 / 5) + 32;
        set => Celsius = (value - 32) * 5 / 9;
    }

    // Read-only property
    public double Kelvin => _celsius + 273.15;

    // Init-only property (C# 9.0+)
    public string Location { get; init; }
}

// Usage
var temp = new Temperature { Location = "Bangkok" };
temp.Celsius = 25;           // Calls setter
Console.WriteLine(temp.Celsius);   // Calls getter: 25
Console.WriteLine(temp.Fahrenheit);// Calls getter: 77
Console.WriteLine(temp.Kelvin);    // 298.15
class Temperature:
    def __init__(self):
        self._celsius = 0
        self._location = None

    # Getter using @property
    @property
    def celsius(self):
        return self._celsius

    # Setter with validation
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Temperature below absolute zero!")
        self._celsius = value

    # Deleter (optional)
    @celsius.deleter
    def celsius(self):
        del self._celsius

    # Computed property
    @property
    def fahrenheit(self):
        return (self._celsius * 9/5) + 32

    @fahrenheit.setter
    def fahrenheit(self, value):
        self.celsius = (value - 32) * 5/9

    # Read-only property (no setter)
    @property
    def kelvin(self):
        return self._celsius + 273.15

    # Property with manual getter/setter methods
    def get_location(self):
        return self._location

    def set_location(self, value):
        self._location = value

# Usage
temp = Temperature()
temp.celsius = 25           # Calls setter
print(temp.celsius)         # Calls getter: 25
print(temp.fahrenheit)      # Calls getter: 77.0
print(temp.kelvin)          # 298.15
temp.fahrenheit = 68        # Calls setter
print(temp.celsius)         # 20.0

3.4.1 Property Patterns Comparison

class Product {
    // Private field with getter/setter
    private _price: number = 0;

    get price(): number {
        return this._price;
    }

    set price(value: number) {
        if (value < 0) throw new Error("Price cannot be negative");
        this._price = value;
    }

    // Read-only (getter only)
    private _id: string = Math.random().toString();
    get id(): string {
        return this._id;
    }

    // Write-only (setter only) - less common
    private _secretCode: string = "";
    set secretCode(value: string) {
        this._secretCode = value;
    }
}
public class Product
{
    // Auto-property (most common)
    public string Name { get; set; }

    // Property with backing field and validation
    private decimal _price;
    public decimal Price
    {
        get => _price;
        set
        {
            if (value < 0)
                throw new ArgumentException("Price cannot be negative");
            _price = value;
        }
    }

    // Read-only auto-property
    public string Id { get; } = Guid.NewGuid().ToString();

    // Init-only property
    public string Category { get; init; }

    // Private setter (read-only externally)
    public int Stock { get; private set; }

    // Write-only property (less common)
    private string _secretCode;
    public string SecretCode
    {
        set => _secretCode = value;
    }
}
class Product:
    def __init__(self):
        self._price = 0
        self._id = id(self)
        self._secret_code = ""
        self._stock = 0

    # Read-write property
    @property
    def price(self):
        return self._price

    @price.setter
    def price(self, value):
        if value < 0:
            raise ValueError("Price cannot be negative")
        self._price = value

    # Read-only property (no setter)
    @property
    def id(self):
        return self._id

    # Write-only (no getter) - uncommon pattern
    @property
    def secret_code(self):
        raise AttributeError("Cannot read secret code")

    @secret_code.setter
    def secret_code(self, value):
        self._secret_code = value

    # Property with private setter (manual pattern)
    @property
    def stock(self):
        return self._stock

    def _set_stock(self, value):  # Private method
        self._stock = value

3.5 Inheritance

        ┌──────────────┐
        │  BaseClass   │
        │  (Parent)    │
        └──────┬───────┘
               │ extends/inherits
        ┌──────▼───────┐
        │ DerivedClass │
        │   (Child)    │
        └──────────────┘
// Base class
class Animal {
    protected name: string;
    
    constructor(name: string) {
        this.name = name;
    }
    
    move(distance: number): void {
        console.log(`${this.name} moved ${distance}m`);
    }
}

// Derived class
class Dog extends Animal {
    private breed: string;
    
    constructor(name: string, breed: string) {
        super(name);  // Call parent constructor
        this.breed = breed;
    }
    
    bark(): void {
        console.log("Woof!");
    }
    
    // Override parent method
    move(distance: number): void {
        console.log("Running...");
        super.move(distance);
    }
}
// Base class
public class Animal
{
    protected string name;
    
    public Animal(string name)
    {
        this.name = name;
    }
    
    public virtual void Move(int distance)
    {
        Console.WriteLine($"{name} moved {distance}m");
    }
}

// Derived class
public class Dog : Animal
{
    private string breed;
    
    public Dog(string name, string breed) : base(name)
    {
        this.breed = breed;
    }
    
    public void Bark()
    {
        Console.WriteLine("Woof!");
    }
    
    // Override parent method
    public override void Move(int distance)
    {
        Console.WriteLine("Running...");
        base.Move(distance);
    }
}
# Base class
class Animal:
    def __init__(self, name):
        self._name = name  # Protected
    
    def move(self, distance):
        print(f"{self._name} moved {distance}m")

# Derived class
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # Call parent constructor
        self.__breed = breed    # Private
    
    def bark(self):
        print("Woof!")
    
    # Override parent method
    def move(self, distance):
        print("Running...")
        super().move(distance)

# Multiple inheritance (Python only)
class SwimmingMixin:
    def swim(self):
        print("Swimming...")

class Duck(Animal, SwimmingMixin):
    pass

3.6 Interfaces & Abstract Classes

// Interface
interface Flyable {
    altitude: number;
    fly(): void;
}

interface Swimmable {
    swim(): void;
}

// Abstract class
abstract class Bird {
    abstract makeSound(): void;
    
    move(): void {
        console.log("Moving...");
    }
}

// Implementation
class Duck extends Bird implements Flyable, Swimmable {
    altitude: number = 0;
    
    fly(): void {
        this.altitude = 100;
        console.log("Flying!");
    }
    
    swim(): void {
        console.log("Swimming!");
    }
    
    makeSound(): void {
        console.log("Quack!");
    }
}
// Interface
public interface IFlyable
{
    int Altitude { get; set; }
    void Fly();
}

public interface ISwimmable
{
    void Swim();
}

// Abstract class
public abstract class Bird
{
    public abstract void MakeSound();
    
    public virtual void Move()
    {
        Console.WriteLine("Moving...");
    }
}

// Implementation
public class Duck : Bird, IFlyable, ISwimmable
{
    public int Altitude { get; set; }
    
    public void Fly()
    {
        Altitude = 100;
        Console.WriteLine("Flying!");
    }
    
    public void Swim()
    {
        Console.WriteLine("Swimming!");
    }
    
    public override void MakeSound()
    {
        Console.WriteLine("Quack!");
    }
}
from abc import ABC, abstractmethod

# Abstract base class (similar to interface)
class Flyable(ABC):
    @abstractmethod
    def fly(self):
        pass

class Swimmable(ABC):
    @abstractmethod
    def swim(self):
        pass

# Abstract class with concrete methods
class Bird(ABC):
    @abstractmethod
    def make_sound(self):
        pass
    
    def move(self):
        print("Moving...")

# Implementation
class Duck(Bird, Flyable, Swimmable):
    def __init__(self):
        self.altitude = 0
    
    def fly(self):
        self.altitude = 100
        print("Flying!")
    
    def swim(self):
        print("Swimming!")
    
    def make_sound(self):
        print("Quack!")

3.7 Key Differences Summary

Feature TypeScript csharp Python
Constructor constructor() Same name as class __init__()
Instance Reference this this self (explicit)
Static Keyword static static @classmethod/@staticmethod
Private Members private keyword private keyword __name (name mangling)
Protected Members protected keyword protected keyword _name (convention)
Inheritance extends : class Child(Parent)
Interface interface + implements interface + : ABC (abstract base class)
Abstract Class abstract keyword abstract keyword ABC + @abstractmethod
Method Override No keyword needed override keyword No keyword needed
Multiple Inheritance No (interfaces only) No (interfaces only) Yes
Access Default public private public

3.8 Practical Example: Complete Class Hierarchy

Here’s a practical example combining all concepts:

         ┌────────────────┐
         │   IStorable    │ (Interface)
         └────────┬───────┘
                  │
    ┌─────────────┼─────────────┐
    │                            │
┌───▼─────┐              ┌──────▼──────┐
│Document │              │  Database   │
│(Abstract)              │  (Concrete) │
└───┬─────┘              └─────────────┘
    │
    ├──────────┬────────────┐
    │          │            │
┌───▼───┐  ┌──▼───┐  ┌────▼────┐
│  PDF  │  │ Word │  │Spreadsheet│
└───────┘  └──────┘  └──────────┘

This hierarchy shows how interfaces, abstract classes, and concrete implementations work together across all three languages.