Programming Paradigms
The competing ways to structure a program: behavior bundled into objects, built from pure functions over immutable data, or driven by streams. Interviewers check that you pick a style deliberately.
on this pageshowhide
explore
- Object-Oriented Programming100 questions
- Objects, State & Behavior14 questions
- Encapsulation & Information Hiding13 questions
- Abstraction11 questions
- Abstract Type vs Interface12 questions
- Inheritance & IS-A10 questions
- Polymorphism & Dynamic Dispatch9 questions
- Composition & Delegation10 questions
- Coupling & Cohesion8 questions
- SOLID Principles2 questions
- Identity, Equality & Immutability11 questions
- Functional Programming214 questions
- Purity & Referential Transparency22 questions
- Immutability21 questions
- First-Class Functions17 questions
- Higher-Order Functions21 questions
- Function Composition17 questions
- Declarative vs Imperative16 questions
- Laziness & Deferred Evaluation20 questions
- Closures & Lexical Capture22 questions
- Recursion and Tail Calls20 questions
- Pattern Matching16 questions
- Effects and Monads22 questions
- Reactive Programming113 questions
- Observable Streams18 questions
- Operators23 questions
- Backpressure18 questions
- Schedulers & Threading23 questions
- Error Handling17 questions
- Reactive Systems14 questions
- Structured Programming30 questions
- Sequence and Basic Blocks5 questions
- Selection and Conditionals5 questions
- Iteration and Loops5 questions
- Scope and Block Structure5 questions
- Subroutines and Procedures5 questions
- Goto Elimination5 questions
- Paradigm Families44 questions
- Imperative Programming5 questions
- Declarative Programming4 questions
- Logic Programming5 questions
- Multi-Paradigm Trade-offs5 questions
- Procedural Style5 questions
- Classification Axes5 questions
- Constraint Solving5 questions
- Dataflow and Array Styles5 questions
- Styles Under Concurrency5 questions
- Metaprogramming96 questions
- Reflection and Introspection17 questions
- Annotations and Decorators17 questions
- Code Generation18 questions
- Macros and Compile-Time Metaprogramming13 questions
- Internal DSLs12 questions
- Dynamic Proxies and Interception19 questions
- Generic Programming95 questions
- Type Parameters16 questions
- Constraints and Bounds16 questions
- Variance18 questions
- Type Erasure and Reification16 questions
- Specialization16 questions
- Parametric Polymorphism13 questions
- Backend Developerroleanchors this topic
- Full Stack Developerroleanchors this topic
- Java Backend Developerroleanchors this topic
- Kotlin Backend Developerroleanchors this topic
- Software Architectroleanchors this topic
- API Designskill
- Android Developerrole
- Server-Side Game Developerrole
- Software Design & Architectureskill
- iOS Developerrole
questions
692 · 7 sectionsA library operation documents that its argument must be a non-empty collection, and a caller passes an empty one. Whose defect is that, and how do Eiffel, Racket, Kotlin and Rust each express and enforce that obligation differently?
basics
~20 sThe caller's. Preconditions are caller obligations. Eiffel's require blames the caller by name, Racket blames the module that crossed the boundary, Kotlin's require throws with no party named, and Rust encodes non-emptiness in the argument type so there is nothing left to check.
Languages disagree about who decides that a concrete type satisfies an abstraction: in Java the type's author declares it, in Go the compiler infers it from method shape, and in Rust a third party may be forbidden from declaring it at all. Compare these models and what each one costs.
basics
~20 sNominal (Java, C#): the type's author writes implements, so retrofitting a library type needs a wrapper. Structural (Go, TypeScript): matching method shape is enough, so a consumer can define the abstraction afterwards. Rust traits are nominal but either side may write the impl, and the orphan rule forces a newtype when neither is local.
Some languages let a class have two supertypes that share a common ancestor, and others refuse. Explain why inheriting a type, inheriting an implementation, and inheriting state are three separate problems, and show how at least three named languages draw the line differently.
basics
~20 sTypes are only obligations, so they union freely. Implementation conflicts are decidable — pick one, order them, or error. State is the hard layer: a shared ancestor's fields must be duplicated per path or shared, and neither default is right for every program.
Two modules each reference the other, forming a cycle in the dependency graph. What does a cycle actually cost you, and which languages refuse to build one versus merely letting it hurt later?
basics
~20 sA cycle fuses its members into one unit: everything in a strongly connected component must be built, tested, versioned and understood together. Go rejects import cycles at compile time with no override; Java and C# allow package-level cycles freely; Python allows the import and fails at runtime on a partially initialised module.
A C library's public header contains only `typedef struct Conn Conn;` plus functions taking `Conn *` — the struct itself is defined in a .c file the caller never sees — even though the C language has no access-control keywords at all. Python is similar in spirit: a leading underscore is a convention, `__all__` names the exported surface, and an attribute written `self.__x` inside `class Cls` is simply stored under the name `_Cls__x` so that a subclass will not collide with it. Meanwhile, a class that declares every field private and adds a matching getter and setter for each satisfies every rule a language is able to check. Are encapsulation and information hiding the same thing? Argue using these cases.
basics
~20 sNo. Encapsulation is a mechanism: bundle state with the operations that reach it. Information hiding is a design property: a module keeps a changeable decision secret. A C header can hide everything with no keywords; getter-and-setter classes hide nothing.
A transfer function returns either a success value or a described failure. What does that return type force on every caller?
basics
~20 sEvery caller must handle the failure case to reach the success value, because the two outcomes are alternative shapes of one returned value. A failure that is thrown instead puts no such obligation at the call site.
A directory lookup returns an empty-or-one-employee context instead of a null reference: what does that force every caller to do?
basics
~20 sAn empty-or-one-value context puts the missing case in the return type, so a caller cannot reach the employee without opening the container: transform the value inside it, or supply a fallback. The possibility of nothing stops being a convention.
In a match expression, what does binding a value's parts inside the pattern give you that reading fields in the branch body does not?
basics
~20 sBinding in the pattern makes one construct do two jobs: it tests that the value has the case's shape and names the parts of that shape at the same time. The branch body starts with named parts instead of shape checks and accessor calls.
What does a compiler's exhaustiveness check on a match over ticket states actually guarantee?
basics
~20 sAn exhaustiveness check proves at compile time that a match handles every variant its type can hold. The payoff comes later: add a variant and every match with a gap fails the build instead of falling through at run time.
In algebraic data types, what distinguishes a payment that is exactly one of card, transfer or credit from a record holding all three?
basics
~20 sA sum type holds exactly one of its variants, tagged so you can tell which; a product type holds a value of every component at once. The payment is a sum, the record of all three is a product.
When a notification pipeline that loads a recipient, records an attempt and calls a carrier is retried after the carrier fails, which steps run again?
basics
~20 sRetrying resubscribes to the source, so every stage above the retry point runs again from the start: the recipient is loaded a second time, a second attempt record is written, and the carrier is called again.
A hand-written stream source emits a failure signal and then keeps pushing values — which rule does that break?
basics
~20 sThe signal grammar: a run carries any number of value signals and then at most one terminal signal, completion or failure, never both. A failure is that ending, not another value, so the source must go silent after it.
A chat screen builds a message stream but no request is sent — what act starts the work, and what does it return?
basics
~20 sSubscribing starts the work; building a stream only describes it. A subscription call attaches a subscriber to the source, triggers whatever the source does to produce values, and hands back a handle the caller uses to cancel that run.
What has happened when a source declared to carry at most one value completes without emitting a value?
basics
~20 sNothing was found and nothing failed: empty completion is a third outcome beside a value and a failure. The caller must decide what absence means here - a default, a fallback source, or an error it raises itself.
A checkout display joins a scan feed and a price feed: why does lockstep pairing emit fewer results than latest-value combination?
basics
~20 sLockstep pairing consumes one value from each source per result, so its rate is the slowest source's rate. Latest-value combination keeps each source's most recent value and emits on every arrival, so its rate is the sum of all rates.
In a loop that processes a list of pending items, what does break do that continue does not?
basics
~20 sbreak ends the loop itself: control resumes at the first statement after it. continue ends only the current pass, skipping the rest of the body and jumping to the loop's next condition test, so later items are still processed.
When a nested block declares a name that an enclosing block already declares, what happens to references to that name inside and after that block?
basics
~10 sThe inner declaration shadows the outer one: inside that block the name resolves to the new declaration, while the outer binding keeps its own value, untouched, and becomes visible again once the block ends.
A compound condition's second operand also writes to a log — when does short-circuit evaluation skip it?
basics
~20 sShort-circuit evaluation stops as soon as the result is decided: a short-circuiting AND skips its second operand when the first is false, an OR when the first is true. The skipped operand never runs, so its log write never happens.
Under call by value versus call by reference, what exactly does a call copy when a routine is handed a sensor record to fill?
basics
~20 sCall by value copies the argument's value into a fresh parameter slot, so assigning to the parameter cannot reach the caller. Call by reference copies the location of the caller's variable, so assigning to the parameter replaces the caller's variable.
Go To Statement Considered Harmful is remembered as goto is evil, but what defect in jump-ridden control flow did it actually name?
basics
~20 sThe objection was about reasoning, not taste. With unrestricted jumps you can no longer describe where a running program has got to using a few coordinates, so a position in the text stops telling you what already happened.
On the state axis of paradigm classification, what are you measuring when you place an unfamiliar language?
basics
~20 sThe state axis measures how far a write travels, not whether assignment exists. You are asking whether a step overwrites a value other code still holds, or produces a new value and leaves the old one intact.
Why does a chat room's shared mutable participant roster force coordination between delivery threads when an immutable roster does not?
basics
~20 sA mutable roster is changed in place, so every reader and every writer must follow one shared discipline or observe a half-applied change. An immutable roster is never written after publication, so a reader that holds one needs no permission from anybody.
In a declarative description of desired state, what does stating the result rather than the steps buy you?
basics
~20 sStating the result hands the evaluator the strategy: it derives which operations run, in what order, and whether any are needed. You gain re-runnability, ordering freedom and portability, and give up step-by-step control of how the work is done.
In an imperative simulation that assigns each entity a new position every tick, what becomes of the previous position?
basics
~20 sAssignment in the imperative model is a destructive update: the storage cell that held the old position now holds the new one. The previous value survives only if the program copied it somewhere before the write.
A payroll subroutine changes the pay amount it was given, but the caller still sees the old value — which parameter-passing mode is in use?
basics
~20 sCall by value: the routine received a copy of the amount, so its assignment updated only the copy in its own activation record. Call by reference, or returning the new value, would make the update visible to the caller.
A marker attached to a class declaration changes nothing on its own — what must exist for it to have any effect?
basics
~20 sAttached metadata is inert: something has to read it. A consumer — a build-time processor, a startup scanner, or a check at the call site — must look for that marker and act on what it says, or nothing happens.
You declare a metadata type marking rate-limited operations. Why does its declaration name the kinds of declarations it may be attached to?
basics
~20 sA metadata type's declaration enumerates the declaration kinds it may be attached to - type, method, field, parameter - and attachments anywhere else are rejected. Target lists turn a misplaced marker into a build error instead of a silent no-op.
In a chained configuration API, what makes one call follow another, and what does the closing call add?
basics
~20 sEach configuring call returns a receiver carrying everything recorded so far, so the next call can be written straight onto it. The closing call is different: it validates the accumulated state and produces the finished result.
In a nested policy notation built from blocks, what does it mean that each block runs against an implicit receiver?
basics
~20 sEach block is a piece of code the enclosing call evaluates against an object it supplies, so unqualified calls inside the block configure that object. Nesting blocks builds a tree: an inner block targets the node its enclosing call just created.
What does a type's run-time self-description contain that lets a renderer build one column per field of an unknown object?
basics
~20 sA loaded type hands back a structured description of itself: its members with their names and declared types, modifier and visibility flags, its supertypes and the contracts it implements, and the type's own run-time identity.
An unrestricted placeholder type in a payroll totalling routine — what may its body do with each element?
basics
~20 sOnly what every type supports: hold it, pass it on, return it. With no limit written, the placeholder is implicitly pinned at the widest type available, so no pay-component operation such as reading an amount is callable on it.
Why does a language that discards type arguments reject a run-time test asking whether a value is a stack of text edits?
basics
~20 sA run-time test can only read what the value still carries, and the discarded argument is not there. Every stack of edits shares one run-time shape, so the test cannot be decided, and the compiler rejects it instead of guessing.
A settings loader is handed the expected type as an argument alongside the key — what does it do with that argument?
basics
~20 sThe type argument is the evidence the run time no longer carries: the loader uses it to choose how to convert the stored text and to check the converted value before returning it, so a mismatch fails at the read.
After compilation on a platform that discards type arguments, what does a stored container value still record about its argument?
basics
~20 sNothing you can ask the value for. The argument is spent during compilation, and what runs is an ordinary container over the erased element shape. Only a declaration, never the object it points at, may keep a written description of it.
A connection type carries a message-type placeholder and a standalone helper carries its own - how long is each fixed?
basics
~20 sA placeholder introduced on the type is chosen once when an instance is created and every member of that instance shares it. A placeholder introduced on one operation is chosen afresh for each call and is scoped to that call.