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;
= GenerateId();
Id }
private string GenerateId()
{
return Guid.NewGuid().ToString();
}
}
// Instantiation
var person = new Person("Alice", 30);
class Person:
# Class variable
= "Homo sapiens"
species
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("Alice", 30) person
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
{
= data["name"].ToString(),
Name = Convert.ToInt32(data["age"]),
Age = data["department"].ToString()
Department };
}
}
// 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"""
= employee_str.split('-')
name, age, dept 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
= Employee()
emp1 = Employee("Alice")
emp2 = Employee("Bob", 25)
emp3 = Employee("Charlie", 30, "Engineering")
emp4 = Employee.create_intern("David")
emp5 = Employee.from_dict({'name': 'Eve', 'age': 28, 'department': 'HR'})
emp6 = Employee.from_string("Frank-35-Finance")
emp7 = Employee.copy_from(emp4)
emp8 = Employee.create_flexible("Grace", department="Marketing") emp9
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() {
.totalCounters++;
Counter
}
// 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()
{
= 0;
totalCounters }
}
class Counter:
# Class variable
= 0
total_counters
def __init__(self):
# Instance variable
self.count = 0
+= 1
Counter.total_counters
# 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)
{
= holder;
AccountHolder = initial;
balance = GenerateAccountNumber();
AccountNumber }
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();
.celsius = 25; // Calls setter
tempconsole.log(temp.celsius); // Calls getter: 25
console.log(temp.fahrenheit);// Calls getter: 77
.fahrenheit = 68; // Calls setter
tempconsole.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!");
= value;
_celsius }
}
// Auto-property (simplified)
public string Unit { get; set; } = "Celsius";
// Computed property (expression-bodied)
public double Fahrenheit
{
=> (_celsius * 9 / 5) + 32;
get => Celsius = (value - 32) * 5 / 9;
set }
// 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" };
.Celsius = 25; // Calls setter
temp.WriteLine(temp.Celsius); // Calls getter: 25
Console.WriteLine(temp.Fahrenheit);// Calls getter: 77
Console.WriteLine(temp.Kelvin); // 298.15 Console
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
= Temperature()
temp = 25 # Calls setter
temp.celsius print(temp.celsius) # Calls getter: 25
print(temp.fahrenheit) # Calls getter: 77.0
print(temp.kelvin) # 298.15
= 68 # Calls setter
temp.fahrenheit 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
{
=> _price;
get
set{
if (value < 0)
throw new ArgumentException("Price cannot be negative");
= value;
_price }
}
// 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
{
=> _secretCode = value;
set }
}
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)
{
.WriteLine($"{name} moved {distance}m");
Console}
}
// Derived class
public class Dog : Animal
{
private string breed;
public Dog(string name, string breed) : base(name)
{
this.breed = breed;
}
public void Bark()
{
.WriteLine("Woof!");
Console}
// Override parent method
public override void Move(int distance)
{
.WriteLine("Running...");
Consolebase.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 {
: number;
altitudefly(): 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 {
: number = 0;
altitude
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()
{
.WriteLine("Moving...");
Console}
}
// Implementation
public class Duck : Bird, IFlyable, ISwimmable
{
public int Altitude { get; set; }
public void Fly()
{
= 100;
Altitude .WriteLine("Flying!");
Console}
public void Swim()
{
.WriteLine("Swimming!");
Console}
public override void MakeSound()
{
.WriteLine("Quack!");
Console}
}
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.