Senior Engineering Interview Handbook / Chapter 966
Appendix B - Coding Language Field Guides
A language-selection guide and standard-library reference for the operations, traps, and rehearsal habits that keep syntax from obscuring reasoning.
Page tools
Choose the language that leaves room for reasoning
A syntax stall costs more than time. It interrupts the explanation, makes a simple data-structure choice look uncertain, and leaves less attention for the invariant and the tests. The best interview language is therefore the one in which ordinary moves have become ordinary.
First confirm that the interview platform accepts the language and supports the version and libraries you expect. Then ask a more demanding question: can you write a map, queue, heap, sort, parser, and small test harness without lookup—and explain their costs, mutation, equality, and ordering behavior? Familiarity from production work is useful, but it is not the same as recall under a short clock.
Choose one primary language. Keep a backup only when a target role or round creates a real need for it. Switching late is justified by a concrete constraint, such as platform support or an API-design exercise that strongly favors another language, not by the hope that different syntax will repair weak problem solving.
Five field guides
Each card is organized for exact lookup. Copy only the one for your chosen language, add the APIs you repeatedly forget, and remove anything you never use.
Python field guide
| Need | Common move |
|---|---|
| Frequency map | collections.Counter or defaultdict(int) |
| Queue | collections.deque |
| Heap | heapq; use (priority, sequence, value) when equal priorities could expose non-comparable values |
| Sort by key | items.sort(key=lambda x: ...) or sorted(items, key=...) |
| Binary search | bisect_left, bisect_right |
| Large sentinel | float("inf") |
Repeated membership checks belong in a set, not a list. A list queue with
pop(0) also pays to move the remaining elements; use deque.popleft().
Remember which operations mutate in place: list.sort() returns None, while
sorted(...) returns a new list.
JavaScript field guide
| Need | Common move |
|---|---|
| Map | new Map() instead of object when keys are not simple strings |
| Set | new Set() |
| Array queue | Maintain a head index; avoid repeated shift() for large queues |
| Sort numbers | arr.sort((a, b) => a - b) |
| Character iteration | for (const ch of s) iterates Unicode code points; it still does not segment user-perceived characters |
| Heap | Bring a small tested heap class if the platform allows helper code |
The default array sort converts values to strings, so numeric work needs a
comparator. Use Map.has(key) to test presence when a stored value could be
0, false, or undefined. For a large queue, a head index avoids repeated
shift() calls; compact the array if retained processed entries would matter
in a longer-lived program.
Java field guide
| Need | Common move |
|---|---|
| Frequency map | HashMap<K, Integer> with getOrDefault or merge |
| Queue | ArrayDeque<T> |
| Heap | PriorityQueue<T> |
| Sort arrays | Arrays.sort(array) |
| Sort lists | list.sort(comparator) |
| String builder | StringBuilder for repeated concatenation |
Primitive arrays and boxed collections have different APIs and equality
behavior. Use Integer.compare(a, b) rather than a - b in a comparator when
overflow is possible, and decide deliberately whether arithmetic needs
long.
Go field guide
| Need | Common move |
|---|---|
| Frequency map | map[T]int |
| Queue | Slice plus head index |
| Heap | Implement container/heap interface or use a prepared minimal heap pattern |
| Sort | sort.Ints, sort.Slice |
| Set | map[T]bool or map[T]struct{} |
| String building | strings.Builder |
Slices can share a backing array. Mutation through one slice may therefore be
visible through another, while append may allocate a new backing array when
capacity is exceeded. If isolation is part of correctness, make the copy
explicit.
C++ field guide
| Need | Common move |
|---|---|
| Frequency map | unordered_map<K, int> |
| Ordered map/set | map, set |
| Queue/deque | queue, deque |
| Heap | priority_queue; use greater<T> for min-heap where suitable |
| Sort | sort(v.begin(), v.end()) with comparator as needed |
| Binary search | lower_bound, upper_bound |
Iterator invalidation depends on the container and operation; do not carry one
rule across vector, ordered associative containers, and unordered
containers. A comparator must define a strict weak ordering. Also watch values
silently converted between signed sizes and unsigned container indices.
Three small traps with large consequences
The language should support the reasoning, but a language-specific default can quietly change the answer. These three examples are worth being able to write and explain from memory.
JavaScript numeric sort
const nums = [10, 2, 1];
nums.sort((a, b) => a - b); // [1, 2, 10]
Without the comparator, the values are compared as strings. An interval, greedy, or binary-search solution can then fail while the sorting call still looks plausible.
Queue in Python
from collections import deque
q = deque([start])
while q:
node = q.popleft()
for nxt in graph[node]:
if nxt not in seen:
seen.add(nxt)
q.append(nxt)
Using pop(0) on a list makes every removal shift the remaining elements. The
algorithm may still be correct, but its implementation no longer has the queue
cost the explanation claims.
Priority in Java
PriorityQueue<int[]> pq = new PriorityQueue<>(
(a, b) -> Integer.compare(a[0], b[0])
);
pq.add(new int[] {distance, node});
Integer.compare states the ordering directly and avoids the overflow risk of
subtracting one priority from the other.
Turn the reference into fluency
Do not memorize this appendix wholesale. Build a one-page card from code you have run. A useful rehearsal takes one familiar problem and changes the language burden while keeping the algorithm steady:
- Write the map, set, queue, heap, sort, and binary-search operations without lookup.
- Implement the problem and state the invariant before the main loop.
- Add empty, singleton, duplicate, and boundary cases that fit that problem; do not add irrelevant tests by ritual.
- Explain which operations mutate, which may copy or alias, and what each important operation costs.
- Reopen the documentation, correct the card, then repeat once without it.
The mistakes from that run belong on the card. A copied catalogue of APIs does not reveal where your recall actually fails.
Use this short sequence before a coding loop:
collections -> sorting -> heap/queue -> strings -> parsing -> tests -> complexity
confirm platform -> name the structure -> state its cost -> show the invariant -> test the boundary
Keep the explanation language-aware but not language-obsessed. Name the behavior that affects the solution: operation cost, mutation, aliasing, equality, ordering, overflow, or text representation. If a helper becomes noisy, simplify it and make its contract explicit. The reader of the code should still be able to see the algorithm.