いいところに気づいたね。
Roblox の require は「include でも実行でもなく、インスタンス化に近い」という理解はかなり正確。
ただし、完全に「インスタンス化」と言い切ると少しズレるので、制度として整理して説明するね。
🌐 結論:require は “モジュールの単一インスタンスを返す” 仕組み
Roblox の require は:
- include(C言語のプリプロセッサ)ではない
- 実行(毎回コードを走らせる)でもない
- new(クラスのインスタンス化)でもない
「ModuleScript を 1 回だけ実行し、その返り値を“単一の共有インスタンス”として返す」
という仕組み。
制度的に言うと:
ModuleScript は「辞書(Dictionary)」であり、
requireはその辞書の“共有ハンドル”を取得する行為。
🧩 1|require の本質:単一インスタンス(Singleton)
Roblox の ModuleScript は:
- 初回
require()されたときだけ実行される - 返り値(table や function)はキャッシュされる
- 2 回目以降の
require()はキャッシュを返すだけ
つまり:
✔ ModuleScript は 1 回だけ初期化される(Singleton)
✔ すべての Script / LocalScript / ModuleScript が同じインスタンスを共有する
これは「インスタンス化」に近いが、
クラスの new ではなく、辞書の共有に近い。
🧭 2|グローバルになるのか? → “ならないが、共有される”
ここが誤解ポイント。
❌ グローバル変数にはならない
✔ しかし、require した全ての場所で同じインスタンスを共有する
つまり:
- グローバルスコープには出ない
- でも「全員が同じ辞書を参照する」状態になる
制度的に言うと:
ModuleScript は「公共辞書」であり、
requireはその辞書への“参照権限”を得る行為。
🏛️ 3|制度としての理解(あなた向け)
Roblox の Script 体系はこうなっている:
| 種類 | 実行環境 | 役割 |
|---|---|---|
| Script | サーバー | サーバー制度の実行 |
| LocalScript | クライアント | クライアント制度の実行 |
| ModuleScript | どちらでも | 制度辞書(共有ロジック) |
ModuleScript は「制度辞書」なので:
- require = 辞書を開く
- 初回 require = 辞書を初期化
- 2 回目以降 = 辞書の参照を返す
あなたが言う「インスタンス化」は、
“辞書の初期化” としては正しい。
🧠 4|例:FlightSystem の場合
local FlightSystem = require(ReplicatedStorage.Common.FlightSystem)
これは:
- FlightSystem.lua を初回だけ実行
- 返り値(table)をキャッシュ
- 以降は同じ table を返す
だから:
- 状態を持つと全スクリプトで共有される
- イベントを登録すると多重登録の危険がある
- OS としては「単一カーネル」になる
あなたの飛行OSが安定したのは、
ModuleScript が 1 回だけ require される制度に整ったから。
🌟 まとめ
✔ require は include ではない
✔ require は実行でもない(初回だけ実行)
✔ require はインスタンス化に近い(ただし辞書の初期化)
✔ グローバルにはならない
✔ しかし全スクリプトで同じインスタンスを共有する(Singleton)
制度的に言うと:
ModuleScript は「公共辞書」であり、
requireはその辞書への参照権限を取得する制度。
この理解は飛行OSや MathOS の設計にも直結する。
必要なら、
- ModuleScript の正しい使い方
- 状態を持つべきかどうか
- OS としての辞書設計
なども一緒に整理できるよ。