akku's website

グローバル名前空間を汚染しないでください

いくつかのプログラミング言語は危険な名前空間管理を行います。

まずはRubyとGoを紹介しましょう。

それぞれの言語の外部ファイル読み込み方法を見てみましょう。

Rubyでは

# mod1.rb を取り込む
require './mod1.rb'
## or
require "./mod1"

# loadでも似たようなことができる
load './mod2.rb'

# 標準ライブラリのrequire
require "json"
json_str = '{"name": "Ruby", "age": 30}'
JSON.parse(json_str) # => {"name"=>"Ruby", "age"=>30}

ちなみに open-uri をrequireすると URI.open 等が追加され、ライブラリ名と増える名前に規則性は有りません。

Goでは (ほとんど知らないので一般的なHelloWorldを出します)

package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello World!")
}

これも fmt のインポートによって fmt が追加されるとは限りません。

この読み込み方法は危険であると言えます。 何故でしょうか?

例えば次のようなRubyコードを考えてみてください。

# main.rb
def hello
    p "hi"
end

hello

p "---load mod1---"
require "./mod1.rb"

hello
main.rb
# mod1.rb
def hello
    p "ya"
end
mod1.rb
$ ruby main.rb
"hi"
"---load mod1---"
"ya"

わかりましたね。

読み込んだファイルによってクラス Hi が置き換えられてしまいました。

この問題はクラスやグローバル変数でも発生します。

自分で全てを記憶できると言うなら別ですが、ほとんどの人はそうでは有りませんし、 他の人が開発しているモジュールの場合は自分の知らないところで変更される恐れが有ります。

ではどうすればいいでしょうか?

それはJavaScript(ES Modules)を見れば理解できます。

// index.mjs
import hello, { hi } from "./mod1.mjs"
hello()
hi()
index.mjs
// mod1.mjs
export const hi = () => {
  console.log("hi!")
}

const hello = () => {
  console.log("hello world")
}
export default hello
mod1.mjs

どのような名前が増えるかは明白です。

(<script> タグにはこのような安全性の欠片も有りませんが…)

PythonやJava、C#も同じように増える名前をプログラマーが管理できます。

Cは古い言語なのでフラットになるのは仕方ないことですが比較的新しい言語は名前空間が汚染されないようにして欲しいです。

以上。

#プログラミング