Your language, side by side
Part of the free Low-Level Design course on LogicWiz, in the chapter: Start here: your machine and Java. The class-diagram exercises run in the app.
Your language, side by side
"I do not mind which language you write the round in. I mind if the design changes with it."
Priya, when Arjun asked whether he must answer in Java
What stays the same, and what changes
Arjun works mostly in Python and asked, "Must I learn all of this in Java?" Priya said no. This course shows Java because its types make a design easy to see. A round can often be answered in Python, C++, Kotlin or C#. This lesson sets Java beside those four.
The same in every language: which classes you choose, what each one owns, how they connect, the interfaces between them, the SOLID principles, the patterns and the diagrams. An interviewer grades these.
This diagram is true in all five languages. Only the way to write Payment changes.
classDiagram
class Payment {
<<interface>>
+pay(paise)
}
class Upi
class Card
Upi ..|> Payment
Card ..|> Payment
What changes: the spelling, what the language checks for you, the names in the standard library, and the tools for threads.
Each table below has one row per language, Java first. Every cell holds a short, valid snippet or a keyword. The snippets use SwiftKart names.
Classes, interfaces, abstract classes and enums
Class and constructor
| Language | How |
|---|---|
| Java | class Product { private final long price; Product(long price) { this.price = price; } } |
| Python | class Product: with def __init__(self, price): self.price = price inside |
| C++ | class Product { long price; public: Product(long price) : price(price) {} }; |
| Kotlin | class Product(private val price: Long) |
| C# | class Product { private readonly long price; public Product(long price) { this.price = price; } } |
Interface
| Language | How |
|---|---|
| Java | interface Payment { void pay(long p); } and class Upi implements Payment |
| Python | no keyword: class Payment(Protocol): with def pay(self, p): ..., and class Upi(Payment): |
| C++ | no keyword: struct Payment { virtual void pay(long p) = 0; virtual ~Payment() = default; }; and class Upi : public Payment |
| Kotlin | interface Payment { fun pay(p: Long) } and class Upi : Payment |
| C# | interface IPayment { void Pay(long p); } and class Upi : IPayment |
Abstract class
| Language | How |
|---|---|
| Java | abstract class Fee { abstract long charge(long p); } and class Flat extends Fee |
| Python | class Fee(ABC): with @abstractmethod above def charge(self, p), and class Flat(Fee): |
| C++ | class Fee { public: virtual long charge(long p) = 0; virtual ~Fee() = default; }; and class Flat : public Fee |
| Kotlin | abstract class Fee { abstract fun charge(p: Long): Long } and class Flat : Fee() |
| C# | abstract class Fee { public abstract long Charge(long p); } and class Flat : Fee |
Enum
| Language | How |
|---|---|
| Java | enum Status { PLACED, PACKED, DELIVERED } |
| Python | class Status(Enum): PLACED = 1; PACKED = 2 |
| C++ | enum class Status { Placed, Packed, Delivered }; |
| Kotlin | enum class Status { PLACED, PACKED, DELIVERED } |
| C# | enum Status { Placed, Packed, Delivered } |
Java, Kotlin and Python enums can hold fields and methods. C++ and C# enums are named whole numbers.
this, static, final and generics
this or self
| Language | How |
|---|---|
| Java | this.price = price |
| Python | self.price = price, where self is the first parameter of every method |
| C++ | this->price = price, because this is a pointer |
| Kotlin | this.price = price |
| C# | this.price = price |
Static members
| Language | How |
|---|---|
| Java | static final int MAX = 50; and static long total(int n) |
| Python | MAX = 50 in the class body, and @staticmethod above def total(n) |
| C++ | static const int MAX = 50; and static long total(int n); |
| Kotlin | no static: companion object { const val MAX = 50 } |
| C# | public const int Max = 50; and public static long Total(int n) |
Final, const and readonly
| Language | How |
|---|---|
| Java | private final long price; can be set once, in the constructor |
| Python | no keyword: @dataclass(frozen=True) blocks changes to the fields |
| C++ | const long price; set in the constructor's initialiser list |
| Kotlin | val price: Long is read-only; var can change |
| C# | private readonly long price; set in the constructor |
Generics
| Language | How |
|---|---|
| Java | class Box<T> { T item; } and List<String> |
| Python | hints only: class Box(Generic[T]): and list[str], and nothing is checked at runtime |
| C++ | template <typename T> class Box { T item; }; |
| Kotlin | class Box<T>(val item: T) |
| C# | class Box<T> { T item; } |
Java removes generic types when the program runs, so you cannot write new T(). C# keeps them. C++ makes a separate copy of the code for each type.
Collections, null and exceptions
List, map and set
| Language | How |
|---|---|
| Java | new ArrayList<String>(), new HashMap<String, Integer>(), new HashSet<String>() |
| Python | [], {}, set() |
| C++ | std::vector<std::string>, std::unordered_map<std::string, int>, std::unordered_set<std::string> |
| Kotlin | mutableListOf<String>(), mutableMapOf<String, Int>(), mutableSetOf<String>() |
| C# | new List<string>(), new Dictionary<string, int>(), new HashSet<string>() |
Python's dict and Kotlin's mutableMapOf keep insertion order. The plain maps of Java, C++ and C# promise no order. When output order matters, use LinkedHashMap, std::map (sorted) or SortedDictionary.
Missing values
| Language | How |
|---|---|
| Java | any object may be null; Optional<String> marks "maybe"; test with s != null |
| Python | None; test with s is None; Optional[str] is only a hint |
| C++ | nullptr for pointers; references are never null; std::optional<std::string> |
| Kotlin | String cannot be null, String? can; s?.length and s ?: "none" |
| C# | string? marks nullable, with compiler warnings; s?.Length and s ?? "none" |
Exceptions
| Language | How |
|---|---|
| Java | throw new IllegalStateException("x"); and catch (IllegalStateException e), plus finally |
| Python | raise ValueError("x") and except ValueError as e:, plus finally: |
| C++ | throw std::runtime_error("x"); and catch (const std::exception& e), no finally |
| Kotlin | throw IllegalStateException("x") and catch (e: IllegalStateException), plus finally |
| C# | throw new InvalidOperationException("x"); and catch (InvalidOperationException e), plus finally |
Only Java has checked exceptions.
Threads and locks
| Language | How |
|---|---|
| Java | synchronized (lock) { count++; } and new Thread(task).start() |
| Python | with lock: after lock = threading.Lock(), and threading.Thread(target=task).start() |
| C++ | std::lock_guard<std::mutex> g(m); and std::thread t(task); |
| Kotlin | synchronized(lock) { count++ } and Thread { task() }.start() |
| C# | lock (obj) { count++; } and new Thread(task).Start() |
The idea is the same everywhere: one thread at a time inside the guarded block. The tools differ. Some parts of this course are Java only: synchronized, ConcurrentHashMap, AtomicInteger, ReentrantLock, checked exceptions, Optional, records and List.of. In another language, read them as the idea and use your language's version, such as lock in C# or std::mutex in C++. The kits in this course are Java files. To use one in another language, translate the contract and the driver by hand, then compare with the same expected output.
Which language should you choose?
Priya's advice is short. Choose the language you write fastest and most correctly under time pressure, if the company allows it. Check the invitation or ask the recruiter, because some companies name the languages. Java is accepted almost everywhere in India, so it is a safe choice. Python is quick to write, but it has no interface keyword, so show your interfaces with a Protocol or an abstract class. C++ gives you more to manage, such as memory and headers. Kotlin and C# suit teams that use them. Do not switch language in the last week. Practise at least five problems in the language you will use.
Now practise moving between languages. Read this Python class, then draw the class diagram that a Java version would have. Python keeps the kind of a transaction as a string. In a diagram, a fixed set of names is clearer as an enum.
class Transaction:
def __init__(self, kind, paise):
self.kind = kind # "TOPUP" or "PAY"
self.paise = paise
class Wallet:
def __init__(self, owner):
self.owner = owner
self.balance_paise = 0
self.history = []
def top_up(self, paise):
self.balance_paise += paise
self.history.append(Transaction("TOPUP", paise))
def pay(self, paise):
if paise > self.balance_paise:
raise ValueError("not enough balance")
self.balance_paise -= paise
self.history.append(Transaction("PAY", paise))
📌 Summary: The design is the same in every language. Syntax, null handling and thread tools differ. Pick the language you code fastest in, if the company allows it.
What Arjun learns next
Arjun now has his laptop ready and knows where each language differs. Next, the course starts with object-oriented programming from zero: classes and objects, the building blocks of every later design.
Check your understanding
- Arjun moves a design from Java to C#. Which part stays the same?
- In a Python round there is no interface keyword. How should Arjun show an interface?
- A lesson uses ConcurrentHashMap, but Arjun will answer in C++. What should he do?
- Arjun is faster in Python than in Java, and the company allows any language. What is the sound advice?