What are forward references in JShell, and how does JShell handle a method that calls something not yet defined?
answer
- Forward reference = use a name before it's declared
- JShell records the snippet as unresolved, not an error
- Auto-resolves when the missing name is declared
- Tracks a dependency graph between snippets
- Convenience only—regular javac would reject it
basics
~20 sA forward reference is when a method you define refers to a variable, method, or type that doesn't exist yet. JShell accepts the definition, marks it as not-yet-runnable, and makes it work automatically once you define the missing piece.
solid answer
~50 sIn ordinary Java, every name a method uses must already be in scope when you compile. JShell relaxes this for interactive work: it allows **forward references**, where a snippet refers to a name that hasn't been declared yet. For example, you can define `int g() { return h() + 1; }` before `h` exists. JShell accepts the declaration but reports that `g` cannot be invoked yet because `h` is undefined; the snippet is recorded in a pending/unresolved state. As soon as you declare `h`, JShell automatically resolves `g` and it becomes callable—you don't redefine `g`. This mirrors the REPL's incremental nature: you sketch top-down, defining the high-level method first and filling in helpers afterward. If you try to call `g` while `h` is still missing, JShell errors clearly that it depends on an undeclared name. The same forward-reference tolerance applies across variables, methods, and types referenced by a declaration.
go deeper
May not know the term; can recognize that JShell sometimes says a method 'cannot be invoked until' another is declared.
Can define a forward reference, explain the unresolved state, and add the missing helper to make it work.
Explains JShell's snippet dependency graph, automatic re-resolution, and why this leniency is REPL-specific and not valid in compiled Java.
Discusses the state-management model (dependency tracking, re-evaluation of dependents on add/remove/change) and its implications when scripting JShell or building tooling on the JShell API.
## The concept of a reference When code uses a name—calls a method, reads a variable, names a type—it is **referencing** that name. In normal compiled Java, the compiler insists that referenced names are **already declared and in scope** at compile time; otherwise compilation fails. You generally must define helpers *before* the code that uses them (or rely on them being in the same class, where order within a class doesn't matter). ## What a forward reference is A **forward reference** is a reference to something that has **not been defined yet**, made *before* its definition appears. In a REPL you naturally want to write the big-picture method first and add the small helper methods later—so you reference names that don't exist yet. ## How JShell handles it JShell is deliberately tolerant of forward references to support this top-down, exploratory style: 1. You enter a declaration that references an undefined name. Example: ``` jshell> int g() { return h() + 1; } | created method g(), however, it cannot be invoked until method h() is declared ``` JShell **accepts and records** the declaration of `g`, but marks it **unresolved**: it tells you `g` exists but cannot be invoked yet because `h` is missing. 2. If you try to call `g()` now, JShell errors clearly: ``` jshell> g() | attempted to call method g() which cannot be invoked until method h() is declared ``` 3. You then declare the missing helper: ``` jshell> int h() { return 10; } | created method h() | update modified method g() ``` JShell **automatically resolves** `g`—it does not require you to retype `g`. Now `g()` returns `11`. ## Why JShell can do this JShell tracks a **dependency graph** among snippets. Each declaration records which other names it depends on. When a missing dependency appears, JShell re-evaluates the snippets that were waiting on it, flipping them from "unresolved" to "valid." Conversely, if you later *remove or change* a dependency so something becomes invalid, JShell can move the dependent snippet back into an unresolved state. ## Scope of the feature Forward references work for any name a declaration depends on—**variables, methods, and types**. It applies to **declarations**, not to a bare expression you're trying to evaluate right now (that needs its names to exist to produce a value). ## Practical value and caution - **Value:** You can program top-down, declaring intent first and details later, which suits design-as-you-go exploration. - **Caution:** This leniency is a REPL convenience and does **not** exist in regular compiled Java. Code that relies on a missing helper will not compile in a real project—so don't mistake "JShell accepted it" for "this would compile."
- What does JShell do when you finally declare the previously-missing method?It automatically resolves and updates the dependent snippet, making it invokable without you retyping it.
- Does this forward-reference tolerance exist in regular compiled Java?No—it's a JShell-only convenience for incremental work; normal javac requires referenced names to be in scope.
saying these in an interview costs you the question
- Thinking JShell rejects any reference to an undefined name
- Believing you must redefine the dependent method after adding the missing one
- Assuming forward references also work in normal compiled Java
- Confusing 'unresolved snippet' with a hard compile error that discards the declaration