背景
Julia v1.0 が2018/8/8にリリースされました。
Julia v1.0は、前バージョンであるv0.6からいくつかの変更点があるのですが、
今のところ世の中にある(とくに日本語の)Julia関連のドキュメントはv0.6以前のものが多いため、v1.0で実行しても動かないことがあります。
そこで、Julia v1.0を使うための注意点など、気づいた点を書いてみたいと思います。
実際には、とくにユーザーとして普通に使うだけならv0.6とv1.0の違いは大したことはないので、たいてい、ほんのちょっと変えれば動くのですが、その「ほんのちょっと」が分からないせいでJulianが減ってしまうのは悲しいので。
Julia v0.7のすすめ
すでに、@bicycle1885さんが書かれていますが、Julia v0.7から非推奨(deprecated)の警告メッセージを削除したものがv1.0になります。したがって、機能的には、ほぼ v0.7≒v1.0と考えてよいです。
上で書いたように、Julia v0.7(≒v1.0)は、前バージョンであるv0.6からいくつかの変更点があるわけですが、Julia v0.7では古い(v0.6時代の)書き方でコードを書くと、「この書き方は非推奨(deprecated)になりました。代わりにこう書いて下さい」という警告メッセージを出します。警告メッセージにしたがって新しい書き方に直せばよいわけです。
それに対して、v1.0では、古い書き方をすると、どう直せばいいのかという警告メッセージを出すことなく、単にエラーになってしまいます。
というわけで、とくにv0.6 時代のドキュメントを参考にしてJuliaのコードを書こうという方は、v1.0よりもv0.7を使うほうがよいかもしれません。
Packageのインストール方法
Julia v1.0が出たばかりの頃は、主要なPackageがv1.0では軒並み動作しないということで、Julia公式のフォーラムが阿鼻叫喚状態になっていたのですが、1か月たって、主要なパッケージはほぼv1.0対応してきているので、普通に使う分にはv1.0で大丈夫になってきています。
v1.0では新しいPackageマネージャーが導入されて、Packageのインストールが劇的に速くなりました。Packageのインストールは、REPL上で]
を押して、Pkgモードに入ってadd Package名
とします。
ちなみに、v0.6時代には、Pkg.add("Package名")
としていたわけですが、v1.0でやるとERROR: UndefVarError: Pkg not defined
とエラーになってしまいます。これは、下に書きますが、多くの標準ライブラリがBase
の外に出されたのにともなってPkg
も外出しされたためでして、最初に、Using Pkg
としておけば、Pkg.add("Package名")
も動作します。
多くの標準ライブラリが明示的にusing
が必要になった
v1.0では、多くの標準ライブラリが、Base
から外に出されました。Base
というのはJuliaを起動したときに自動的に読み込まれるパッケージなわけですが、ここから外に出された標準ライブラリを使うには、using ライブラリ名
と明示的に記述する必要があります。
例えば、
-
@printf
を使うにはusing Printf
する - 線形代数関係の関数など(
inv
やdet
、Diagonal
、Symmetric
、eigvals
)を使うには、using LinearAlegebra
- 日付関連の関数(
now
やDate
など)を使うには、using Date
など、といった具合です。
標準ライブラリの一覧は、公式ドキュメントのStandard Libraryの項にあります。
とにかく、v0.6時代のコードを、v1.0動かしてERROR: UndefVarError
と怒られたら、using 〇〇
が必要な可能性が非常に高いです。(Julia v0.7を使っていれば「この機能を使うには、using 〇〇
をしてね」という警告メッセージがでます。)
Scopeルールの変更
v0.6 → v1.0の変更点のうちでハマる可能性が高い罠に、変数スコープの変更があります。この変更はそれ自体は理にかなったものなのですが、REPL(普通にJuliaを起動してJulia>
というプロンプトがでている画面)で、インタラクティブにJuliaを使う場合には注意が必要です。
たとえば、REPL上で、1から10までの数字の和を計算しようとして、Forループを使うと
julia> a = 0
for i in 1:10
a += i
end
ERROR: UndefVarError: a not defined
となります。
正しくは、
julia> a = 0
for i in 1:10
global a += i
end
julia> a
55
とする必要があります。
Julia v1.0の変数スコープについての説明がここにありますが、かいつまんで言うと
- Juliaには、グローバルスコープとローカルスコープの2種類のスコープがある
- for、while、let、関数定義などは新しいローカルスコープを導入する
- ローカルスコープはいくらでもネストできる。
- ネストされた内側のローカルスコープの中で、外側のローカルスコープで定義された変数を読み書きできる。
- ローカルスコープの中では、グローバルスコープで定義された変数を読むことはできるが、(デフォルトでは)書き変えることはできない
- ローカルスコープの中で、グローバルスコープの変数を書き換えたい場合には、
global 変数名
とグローバルスコープの変数を参照するということを明示的に記述する必要がある。
となります。とくに注意が必要なのはルール5でして、REPLでの実行は、つまりグローバルスコープでの実行なので、グローバルスコープで定義された変数a
を、for
文で導入されたローカルスコープ内で書き換えることができないためにエラーになったわけです。
正しく動作させるには、ルール6にしたがってglobal a += 1
と変数a
がグローバルスコープで定義された変数であることを明示する必要があります。
別の解決策としては、
julia> let
a = 0
for i in 1:10
a += i
end
a
end
55
のように、ルール3,4にしたがって、let
でローカルスコープを導入して、その中でfor
を使うでもよいです。ネストされたローカルスコープの内側から、外側のローカルスコープ(let
で導入されたローカルスコープ)で定義された変数a
を読み書きできます。関数定義でもローカルスコープが導入されるので、let
で囲む代わりに処理を関数にしてしまうでもよいです。Juliaでは、グローバルスコープで計算しないで可能な限り関数にするというのが鉄則なので(関数化しないとJuliaの強力な最適化機構が効きません)、関数化するほうが真っ当な解決策でしょう。
この新しい変数スコープの仕様は、とくにREPL上では非常に使いにくいということで、issueがあがっているので、おそらく、近いうち(Julia v1.1?)には、REPL上で実行するときだけは特別扱いされて、global
が必要なくなると思われます。
ちなみに、Jupyter上ではJuliaを実行する場合には、すでに、特別扱いがされているので、global
をつけなくても動きます。