Code Understanding › Code Explanation

Michael BrenndoerferFebruary 2, 20265 min read
Language AI HandbookAll chapters
Part 47 of 67Code Generation
Chapter 358Code Understanding › Code Explanation
Reading section 3 of 13 · Code Explanation · 5 minSection 3 of 13 · 5 min

Book contents

Section 3 of 13 · 5 min read

Code Understanding › Code ExplanationOne section · Sections in this chapter3 / 13 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

The most accessible code understanding task is explanation: given a function or snippet, produce a natural language description of what it does.

What Explanation Requires

Useful explanation goes beyond surface translation. Turning for i in range(len(arr)) into "iterates over the indices of the array" is a start, but it tells the reader nothing they could not read themselves. Good explanation addresses four distinct concerns:

  • What the code does: the observable behavior, inputs, outputs, and side effects
  • Why it does it that way: the design choices, their rationale, and what alternatives exist
  • When it is appropriate to use: the preconditions, post-conditions, and edge cases
  • What it does not do: the cases it does not handle, the failure modes, and the assumptions it makes

The difference between restating code and explaining code is similar to the difference between reading a mathematical proof step-by-step versus understanding the idea behind it. The former is faithful but not illuminating; the latter requires semantic understanding. An explanation of a binary search function that just says "checks if the middle element matches the target and narrows the range" has captured the mechanics but missed the insight: binary search works because each comparison eliminates half the remaining candidates, giving logarithmic time complexity. The explanation becomes useful only when it communicates that insight.

This is why generating good explanations is hard for language models. The model must produce output that is simultaneously faithful to the code, informative beyond what the code itself says, and calibrated to the background knowledge of the reader. Getting all three right requires a rich model of both code semantics and the pragmatics of communication.

Explanation in Practice

Models generate explanations by treating code as the prompt and generating natural language as the completion. Fine-tuning on code-documentation pairs (such as those mined from GitHub repositories where functions appear alongside docstrings) substantially improves explanation quality over zero-shot prompting.

The CodeSearchNet dataset, introduced by Husain et al. (2019), assembled 6 million code-documentation pairs from GitHub across six programming languages. It became a standard training and evaluation resource for code-to-natural-language tasks. Models fine-tuned on CodeSearchNet can produce fluent summaries of short functions with reasonable accuracy.

Longer code units are harder. Length alone does not explain the difficulty: a class has methods, attributes, inheritance relationships, and invariants that interact. A good explanation of a class is not the union of explanations of its methods; it requires understanding how the parts compose into a coherent design. The explanation of a class like BinarySearchTree is not "a class with insert, delete, and search methods" but rather "a data structure that maintains a sorted binary tree for efficient search operations, with O(log n) average-case time complexity when the tree is balanced." This design-level description requires understanding how the parts compose, which is beyond the reach of models that process each method in isolation.

Instruction-tuned models prompted with explicit tasks, such as "Explain this function's purpose, time complexity, and edge case behavior in three sentences," produce more focused explanations than models prompted simply with the function text. The prompt structure guides the model toward the aspects of explanation that matter most.

Explanation Quality and Hallucination

One of the most dangerous failure modes in code explanation is confident hallucination: the model produces an explanation that sounds accurate but describes behavior the code does not have. This is not random noise; the model is filling in what the function "should" do based on its name, structure, and patterns from training. For common patterns, this works. For less common ones, the model may silently substitute its prior expectation for careful analysis.

Consider a function named sanitize_input that, due to a missing branch, fails to sanitize one particular injection pattern. A model that has seen thousands of correct sanitization functions may explain this function as "validates and cleans user input to prevent injection attacks," which is exactly wrong in the case that matters. The developer who reads this explanation and trusts it has been misled in a security-critical context.

Grounding explanations in symbolic analysis can reduce this risk. If the explanation is generated alongside dynamic analysis results (what the function returns for a set of test inputs), the model can be required to produce explanations consistent with observed behavior rather than expected behavior. This approach is more expensive but substantially more reliable for high-stakes code.

Worked Example: Explaining a Utility Function

Consider this Python function:

In[4]:
Code
def find_duplicates(lst):
    seen = set()
    duplicates = set()
    for item in lst:
        if item in seen:
            duplicates.add(item)
        else:
            seen.add(item)
    return sorted(duplicates)

A surface translation might be: "Uses two sets, seen and duplicates, iterates over the list, adds items to seen or duplicates depending on whether they were seen before, and returns the sorted duplicates set."

A semantic explanation would be: "Returns the sorted list of elements that appear more than once in the input. The function uses a hash set for O(1) membership testing, which gives overall O(n) time complexity. It finds duplicates in a single pass without modifying the original list. Note that it only detects elements appearing at least twice; it does not count how many times each appears."

The second explanation requires understanding the algorithmic intent, the data structures, the complexity, and the behavior on edge cases like empty lists or lists with no duplicates. This level of explanation helps a reader encountering unfamiliar code. Notice also that the second explanation identifies what the function does not do: it does not count occurrences, so an element appearing three times is indistinguishable from one appearing twice. This negative information is just as important as the positive description.