Explicit end-of-use: the 'forget' keyword

Marek Kozieł develop4lasu at gmail.com
Mon Jan 26 06:31:31 UTC 2026


Hi,

Java lacks a way to express intentional end-of-use.

This leads to:
- accidental reuse of values that are no longer semantically valid
- unclear intent during code review
- refactoring hazards when scopes expand

I’m interested in revisiting and refining this concept (raw form was
discussed during Project Coin in 2009). The goal is to better understand
the problem space so that, if and when the benefits clearly justify it, a
well-formed direction could be considered.



OVERVIEW

FEATURE SUMMARY:
The forget keyword prevents further access to a variable, parameter, or
field within a defined scope, attempts to access the variable in forbidden
scope will result in a compile-time error.

MAJOR ADVANTAGE:
This change makes variable and resource lifetimes explicit and
compiler-enforced, improving code clarity and predictability.

MAJOR BENEFITS:
Allows explicitly removing a variable from the active context (in terms of
accessibility), which is currently:

impossible for final variables (only comments can be used),
impossible for method parameters (except assigning null to non-final
references),
impossible for fields,
cumbersome for local variables, requiring artificial blocks (extra lines
and indentation).

Makes it possible to explicitly declare that a variable should no longer be
used or no longer represents valid data in the current scope, including
cases where continued use would be undesirable or error-prone (like when
there is method created for this purpose).
Preserves code quality over time, avoiding degradation caused by = null
assignments, comments-only conventions, or artificial scoping blocks.

MAJOR DISADVANTAGE:
The introduction of a new reserved keyword introduces potential source
incompatibilities with existing codebases that define identifiers named
forget.

ALTERNATIVES:
Java currently provides only scope-based lifetime control (blocks and
try-with-resources). It lacks a general, explicit, and compiler-enforced
mechanism to terminate variable usability at an arbitrary point within an
existing scope.

EXAMPLES

Simple and Advanced Examples:
forget var; // Variable is forgotten for the remainder of the current block
or method (default behavior)
forget var : scope; // Variable is forgotten inside the entire scope
statement

where scope could potentially be : if, for, while, try, label, static,
method

forget (var1, var2, ...); // Specified variables are forgotten for the
remainder of the current block

forget this.field; // Specified field are forgotten for the remainder of
the current block

forget (var1, var2, ...) { /* code */ }; // Specified variables are
forgotten only inside the enclosed block

void handleRequest(String request, String token) {    if
(!isTokenValid(token)) {
      throw new SecurityException("Invalid token");
   }

   authorize(request, token);

   forget token /* used & contains sensitive info */;

   process(request);

   logger.debug("token was: " + token); // Compile-time error: 'token' has
been forgotten and cannot be used
}

public Product(String name) { // constructor
   this.name = name.trim().intern();
   forget name; // From now on, only use 'this.name'!

   // other constructor commands...

   if (isDuplicate(this.name)) { ... } // Always canonical, never raw input
   if (isDuplicate(name)) { ... } // Compile-time ERROR!
}

   // * Forces usage of the correctly prepared value (this.name) only.
   // * Prevents code drift, maintenance bugs, or copy-paste errors that
reference the raw parameter.
   // * Makes the constructor safer: no risk of mismatches or inconsistent
logic.
   // * Reads as a contract: "from here on, don't touch the original
argument!"
Next Version Examples:
forget ClassName.field;
forget variable.field;
forget (!variable); // Limit allowed variables to ones that are directly
specified

DETAILS

SPECIFICATION:
   forget [ Identifier | ( IdentifierList ) ] [ : Scope | { block }];

   IdentifierList:
   Identifier {, Identifier}

   Identifier:
   [ VariableIdentifier | this.FieldIdentifier ]

The forget statement forbids any further use of the specified identifier in
all subsequent expressions and statements within the declared scope in
which the identifier would normally be accessible.

COMPILATION:
The variable is not physically erased (except it may be if not a field);
rather, it is protected from any further access after the forget statement.
Additionally, retaining the variable in the scope (but inaccessible)
prevents situations where a developer tries to create a new variable with
the same name after removing the forget statement, thereby enforcing
consistent usage and avoiding hidden bugs.

TESTING:
Testing the forget statement is equivalent to testing variable scope after
exiting a block—the variable becomes inaccessible. For fields, forget
enforces access control, ensuring the field cannot be used within the
specified scope for the remainder of its block or method.LIBRARY

COMPATIBILITY
The introduction of a new keyword (forget) may cause conflicts in codebases
where forget is already used as an identifier. There are no other
compatibility impacts.

REFERENCES
Current draft  »
https://lasu2string.blogspot.com/2026/01/Java-forget-keyword.html
Reddit discussion »
https://www.reddit.com/r/java/comments/1qhhf9y/proposal_introducing_the_forget_keyword_in_java/
Draft from 2009  »
https://lasu2string.blogspot.com/2009/03/forget-keyword-proposal_27.html
Project coin 2009 discussion entry  »
https://mail.openjdk.org/pipermail/coin-dev/2009-March/001093.html
JDK-6189163  » https://bugs.openjdk.org/browse/JDK-6189163


PROBLEMS

Backward Compatibility: Introducing forget as a new reserved keyword will
cause compilation errors in existing code that already uses forget as an
identifier (variable, method, class, etc).
Tooling Lag: IDEs, static analysis tools, and debuggers must all be updated
to handle the new keyword and its effects on variable visibility.
Code Readability: Misuse or overuse of forget could make code harder to
maintain or follow if not used judiciously, especially if variables are
forgotten in non-obvious places.
Teaching and Onboarding: This feature introduces a new concept that must be
documented and taught to all developers, which can increase the learning
curve for Java.
Migration Complexity: Automatic migration of legacy code may be
challenging, particularly for projects that rely on forget as an existing
identifier or which have established conventions for variable lifetime.
Interaction with Scoping and Shadowing: The detailed behavior when
variables are forgotten, shadowed, or reintroduced in inner scopes may lead
to confusion and subtle bugs if not carefully specified and implemented.
Reflection and Debugging: While reflective APIs themselves are not
impacted, developers may be surprised by the presence of variables at
runtime (for debugging or reflection) that are "forgotten" in the source
code.
Consistency Across Language Features: Defining consistent behavior for
forget in new contexts (e.g., lambdas, anonymous classes, record classes)
may require extra specification effort.
Edge Cases and Specification Complexity: Fully specifying the semantics of
forget for all cases—including fields, parameters, captured variables in
inner/nested classes, and interaction with try/catch/finally—may be complex.
Unused Feature Risk: There is a risk that the forget keyword will see
little real-world use, or will be misunderstood, if not supported and
encouraged by frameworks or coding standards.

THE RIGHT AND THE WRONG WAY

During the discussion, it became clear that the main conception of usage
was not approached from the right angle.
For example, the request JDK-6189163: New language feature: undeclare
operator made a similar suggestion. Unfortunately, much of the focus was on
"destroying" variables as a matter of code complexity and maintenance. This
focus is problematic for several reasons:

The compiler can already release variables when they are no longer needed.
Focusing on disposing bytes of data is really a bad step as it shouldn't be
a concern in the first place.
Focusing on variable usability in this way actually decreases
maintainability, since both current and future modifications would require
additional checks to unlock variables or identify where a variable has been
"undeclared" in the middle of code. This complicates code changes
unnecessarily.



At the same time, we should highlight that many language features are, to
some extent, syntactic sugar from a usability perspective:

Block-based local variable scoping
 - Enhanced for Loop
 - Final guard
 - Generics
 - Lambdas
 - Records
 - Switch Expressions
 - Text Blocks
 - Try-With-Resources
 - ... and many more

Each of these features can absolutely be used in the wrong way, which may
decrease code quality.
On the other hand, when used properly, they can significantly reduce
cognitive load and the time required for analysis, refactoring, and
modification - and this path the change will aim to follow.

So we should focus on situations where forget is actually beneficial in the
short or long term:

When code is actively being developed -especially complex one - there are
situations where removing unnecessary variables from the context is
beneficial. It's entirely possible that in the final version these
variables will be placed into proper scopes with no need of forget, but
until then forget would serve an important purpose during development.
When modifying long or complex code—especially if an issue arises from the
incorrect reuse of a variable: We could safeguard the variable with a
comment explaining its intended use and the change made. This targeted fix
is preferable to an unannotated quick fix (which leaves confusion for
future maintainers) or an extensive refactor, which could disrupt code
history and introduce new errors.
Writing security-sensitive code where resources need to be released in a
specific order that cannot be enforced using classic block structures.
Explicitly excluding class variables from the current method scope when
ussage could be harmfull(for example in efficiency aspect), helping to
prevent accidental usage and improve code clarity.



SIMPLIFIED VERSION

Problem: Handling variable "forgetting" via scope control can introduce
unnecessary complexity. To address this, an alternative version without
scope customization could be considered.

Simplified Solution:

Instead of customizing scopes, forget could apply to the method/block scope.
Caveat: It does NOT work for mutually exclusive scopes like parallel
branches (if-else, switch-case). In those, you must restate forget in each
branch.

void handleRequest(String request, String token) {
   if (!isTokenValid(token)) {
      throw new SecurityException("Invalid token");
   }
   if (forceLogOut()){
      logOut(request, token);
      forget token; // prevent usage in the rest of this block and after
the if-else
      ...
   } else {
      authorize(request, token);
      forget token; // 'forget' needs to be restated here
      ...
   }
   logger.debug("token was: " + token); // Compile-time error!
}
This approach is more rigid and resistant to refactoring mistakes if block
scopes change.
If more flexibility is needed, a more complex form like forget var : label;
(for better control) can be introduced as an advanced feature.

SUMMARY

The forget keyword represents a natural evolution of Java's commitment to
clear, explicit, and compiler-enforced language rules. By allowing
developers to mark variables, parameters, or fields as no longer usable
within a defined scope, forget makes variable lifetimes and resource
management visible and deliberate. This approach eliminates ambiguity in
code, prevents accidental misuse, and reinforces Java’s tradition of making
correctness and safety a language guarantee, not just a convention. Like
Java’s robust type system and scoping mechanisms, forget enhances code
clarity, maintainability, and reliability.

--
Greetings
Marek Kozieł ( Lasu )
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20260126/81914844/attachment-0001.htm>


More information about the amber-dev mailing list