Skip to content

Adding an import in a later cell nullifies variables defined in earlier cells #119

Description

@andrus

Summary

Generated by Claude

When a variable is defined in one cell and then new import statements are evaluated in a subsequent cell, the variable's value is reset to null. Any code in later cells that references that variable then fails with a NullPointerException. Combining all imports into a single upfront cell avoids the problem, but that is an unreasonable constraint for interactive notebook use.

Steps to Reproduce

Run the following cells in order:

Cell 1 — initial import

import io.bootique.*;

Cell 2 — define a variable

var bq = Bootique.app("-c", "my.yml")
    .autoLoadModules()
    .createRuntime();

Cell 3 — add more imports in a new cell

import io.bootique.config.jackson.*;
import io.bootique.config.*;

Cell 4 — use the variable defined in Cell 2

JsonConfigurationFactory cf =
    (JsonConfigurationFactory) bq.getInstance(ConfigurationFactory.class);

Actual Behavior

Cell 4 throws a NullPointerException because bq is null:

java.lang.RuntimeException: java.lang.NullPointerException, Cannot invoke
"io.bootique.BQRuntime.getInstance(java.lang.Class)" because "REPL.$JShell$30B.bq" is null
|       at org.dflib.jjava.kernel.execution.CodeEvaluator.evalSingle(CodeEvaluator.java:145)
|       ...
|   Caused by: jdk.jshell.EvalException: Cannot invoke
"io.bootique.BQRuntime.getInstance(java.lang.Class)" because "REPL.$JShell$30B.bq" is null
|       at .(<Anonymous>#35:1)

The internal REPL class name ($JShell$30B.bq) reveals that JShell has re-created the snippet class for bq's enclosing context, leaving the field uninitialized.

Expected Behavior

Adding imports after a variable has been defined should not affect the value of that variable. The notebook's interactive contract is that each cell runs in the existing state; importing new classes is purely additive and should not invalidate prior bindings.

Workaround

Placing all import statements in a single cell before defining any variables avoids the issue:

// Cell 1 — all imports together
import io.bootique.*;
import io.bootique.config.jackson.*;
import io.bootique.config.*;
// Cell 2 — variable definition (safe now)
var bq = Bootique.app("-c", "my.yml")
    .autoLoadModules()
    .createRuntime();

This works, but is impractical for real notebook workflows where imports are naturally discovered and added incrementally.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions