3.

Julia「invalid redefinition of constant」エラーの原因と対処(Revise.jl

編集
この記事の要点
  • 原因: Julia の Module 内で struct / 定数を2 回目以降に再定義しようとした
  • Julia の型・const はセッション内で再定義不可(パフォーマンスのため)
  • 対処1: Revise.jl を使って自動再読み込み。using Revise; includet("file.jl")
  • 対処2: REPL / Julia プロセスを再起動
  • 対処3: structmutable struct に変更(フィールド追加には型再定義必要なので限定的)
  • 対処4: Module を別の名前で再定義UserApp2

エラーの全文

ERROR: LoadError: LoadError: invalid redefinition of constant UserApp
Stacktrace:
 [1] top-level scope
   @ ~/myproj/src/UserApp.jl:3
 [2] include(::String)
   @ Main ./Base.jl:419
 [3] top-level scope
   @ ~/myproj/main.jl:5
in expression starting at /home/user/myproj/src/UserApp.jl:3
in expression starting at /home/user/myproj/main.jl:5

なぜ起きるか

Julia では structconst 宣言は1 セッション内で 1 度しか定義できません。以下のような状況で発生します:

# UserApp.jl
struct UserApp
    name::String
    id::Int
end

# REPL でこのファイルを include
julia> include("UserApp.jl")  # 1 回目: OK

# ファイルを編集して field を増やす
struct UserApp
    name::String
    id::Int
    email::String   # ← 追加
end

# 再度 include
julia> include("UserApp.jl")  # 2 回目: ERROR
# ERROR: invalid redefinition of constant UserApp

Julia は struct = const 定数 として扱うため、型の再定義は許可されません。これはすでに生成されたインスタンスとの整合性を守るための制約です。

対処1: Revise.jl で自動再読み込み(推奨)

Revise.jl は Julia 開発で必須のパッケージ。ファイルの変更を検出して自動的にコード再読み込みする仕組みで、関数の再定義は問題なく動きます。型の再定義はModule ごと差し替える機能で対応されます。

# 初回インストール
using Pkg
Pkg.add("Revise")

# 使い方: 起動直後に必ず最初に
using Revise

# ファイルを includet (track 付き include)
includet("UserApp.jl")

# 以降、UserApp.jl を編集して保存すると自動反映
# 関数の変更: 自動再定義 OK
# struct の変更: Revise が新セッション化で対応

自動起動の設定: ~/.julia/config/startup.jl に以下を書いておくと REPL 起動時に常に Revise が読み込まれます:

# ~/.julia/config/startup.jl
try
    using Revise
catch e
    @warn "Error initializing Revise" exception=(e, catch_backtrace())
end

対処2: Julia プロセス再起動

最も確実。Revise を使わない、または使っていても解決しない場合:

# REPL から
julia> exit()

# または Ctrl+D

# 再起動
$ julia
julia> include("UserApp.jl")  # クリーンな状態から

VS Code の Julia 拡張ならJulia REPL を Restart で同等の操作ができます (コマンドパレット: "Julia: Restart REPL")。

対処3: mutable struct への変更を検討

フィールド値を変えたいだけなら mutable struct に切り替えるとインスタンス作成後にフィールド更新可能になります。ただしフィールド構成自体の追加には型再定義が必要なので、起動済セッションで完結はしません。

# 通常の struct (immutable)
struct UserApp
    name::String
    id::Int
end

u = UserApp("Alice", 1)
u.name = "Bob"  # ERROR: setfield!: immutable struct of type UserApp cannot be changed

# mutable struct
mutable struct UserApp
    name::String
    id::Int
end

u = UserApp("Alice", 1)
u.name = "Bob"  # OK

対処4: Module 名を変えてバージョニング

緊急回避策。設計上イマイチですが REPL 開発初期で手早く試したいとき:

# UserApp.jl
module UserAppV2     # ← V2 に
struct UserApp
    name::String
    id::Int
    email::String
end
end

# 別名 import
using .UserAppV2
u = UserAppV2.UserApp("Alice", 1, "a@example.com")

const 変数の場合

同じエラーは const 定数の再代入でも起きます:

const MAX_USERS = 100

# 同セッション内で再代入
const MAX_USERS = 200
# WARNING: redefinition of constant MAX_USERS. This may fail, cause incorrect answers,
# or produce other errors.
# ERROR: invalid redefinition of constant MAX_USERS

# 型が同じなら警告のみで通る場合あり(Julia 1.10+)
# 型が違うと必ずエラー

# 解決: const を外す(パフォーマンス低下)
MAX_USERS = 100
MAX_USERS = 200  # OK

# または Ref を使う
const MAX_USERS = Ref(100)
MAX_USERS[] = 200  # OK

各対処の使い分け

状況推奨対処
開発中・対話的に試行錯誤Revise.jl + includet()
本番デプロイ・1 回限り実行そもそもエラーが出ない(毎回新プロセス)
Revise 使っているのにダメREPL 再起動
フィールド値だけ書き換えたいmutable struct
急いで動かしたいModule 名を変える(妥協)

FAQ

Q: なぜ Julia は型を再定義できないのか
A: JIT コンパイル済みコードとの整合性のため。既存インスタンスのメモリレイアウトと、新しい型定義のレイアウトが衝突する可能性があります。Python のような完全動的化を諦めることで C 並みの速度を実現しています。

Q: Pluto.jl を使っているがこのエラーが出る
A: Pluto はリアクティブノートブックで Revise 不要のはずですが、複数セルにまたがって同じ型を定義しているとエラーになります。1 セルに 1 型でまとめてください。

Q: Project に組み込んだパッケージで起きる
A: パッケージは通常 using で 1 度だけ読まれるので起きにくいですが、ファイル直接 include していると発生します。パッケージ化して using MyPackage 経由にすると Revise が綺麗に動きます。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. ERROR: UndefVarError: Genie not defined
  2. ERROR: AssertionError: haskey(hashes, uuid)
  3. ERROR: LoadError: LoadError: invalid redefinition of constant UserApp