Julia内部を改造する準備をしてみる


最近、楽しんでいるのがJulia langです。 
と言う前提はどうでも良いのですが。。。
毎日Juliaで遊んでいると元自作言語屋としては内部構造が気になって仕方ない。 
GitHubから取り込んでソースコードを読んでいるうちに改造したくて仕方なくなってしまいました。

当初は修正してはフルビルドの繰り返し、なんとか時短する方法が無いかと悩んでおりました。 
そこで、https://discourse.julialang.org で質問したところ、中の人?から色々とアドバイスを頂きましたので、Qiitaにも展開致します。 

ところでJuliaの内部構造・改造に興味がある人が何人居るのだろうか? 

質問としては、baseの下にあるモジュールを変更したいのだがフルビルドは時間がかかるので、なんか良い方法は無いか?という感じです。

最初の回答は
Revise.jlが使えるよ。という返事。
Revise を調べると https://timholy.github.io/Revise.jl/stable/#What-Revise-can-track-1
使えそう。 
だいたい名前がRevise(改訂・修正)だし。他にも コミッター直々から@eval を使う方法も良い、という返事
Juliaに組み込まれているBasicな関数を自分で改造する方法は色々と有るという事ですね。
中の人達?、結構優しい。

私が行った手順は
ー ドキュメントの該当部分を探して読む(これが結構重要です)
ここから以下がポイントと推定
  ー any package that you load with import or using
  ー any script you load with includet
  ー any file defining Base julia itself (with Revise.track(Base))
  ー 他にも云々、云々と書いてある

要は、
 1.Revise.jlをパッケージとして読み込む
 2.includetでターゲットソースコードを読み込む
 3.更にRevise.track()を使うと修正した時に即座に反映されるので楽。
という事です。

当方の環境は以下です。OS OSX Catalina 開発環境 JuliaPro 1.4.2-1  従って ATOM + Juno + Julia 1.4.2 とほぼ同等になります

では、やったこと。
Reviseは、パッケージモードから add Reviseで追加

テスト用のソースコード test.jlは簡単にこんな感じ

test.jl

using Revise

includet("unicode.jl")
Revise.track(Base.Unicode)

textwidth('⛵')

textwidth('⛵’)は、指定された文字、文字列の文字幅?を求める関数で、base/strings/の中にある unicode.jlの中に定義されています。何故、この関数に目をつけたかというと、Unicode関連は他の部分に影響する範囲が狭い?と推定、修正に失敗したときのダメージを最低限に抑えるためです。
更にソースコードの中で、他のソースをincludeしていなかったからです。
unicode.jlの中で、絵文字が可愛いので、この関数をターゲットにしました。
それ以上の意味は有りません。

unicode.jlは、GitHubから持ってきたソースファイルを作業用ディレクトリにコピー
AtomでOpenし、ちょっと修正

unicode改造.jl
function textwidth(c::AbstractChar)
    show("debug") # この行を追加 REPLに文字が出力される事を期待
    ismalformed(c) && return 1
    Int(ccall(:utf8proc_charwidth, Cint, (UInt32,), c))
end

実際のソースコードは、1.4.2用の unicode.jl 231行から始まるブロックです。読込後、Atom(Juno)からブレークポイントの設定を行いました。

テスト用のソースコード test.jlをアクティブにして、textwidth('⛵’)にブレークポイントの設定
既に textwidth内部にブレークポイントを設定しているので不要ですが、これで覚悟と気合いを注入 (特に意味ないですが重要)


Test.jlとunicode.jlは同じディレクトリに格納。環境によっては includetの読込先が異なるかもしれないと思いフルパスを指定したところ、ファイルが見つからないというエラー。
~/からのパスを入れてもエラー。
今居るディレクトリからの相対位置しか見ていない模様です。残念。
で、念のために、Juliaを再起動(重要)してから、Run with Debugで textwidthに進んでみると

おー、無事にtextwidth改造版の中で止まっている。うれしい。
デバッガの使い方は省略します。

なぜか、REPLの出力に何回も “debug"が表示されますが、デバッガでトレースすると1回しか通過していないので表示上の問題と判断、深く追求しませんでした(面倒そうなので諦めた)

後は、コミュニティに貢献できるような改造が出来れば良いのですが、それは別の話。

悩んでいるのは、Revise.track(Base.Unicode)なのか、Revise.track(Base)がベストなのか、行った範囲では同一の結果が得られています。
Revise.jlを追っかければ良いのですが、安心したので後まわし。

最後に、Juliaの中の人?からは、Base.jl 以下の修正には十分注意するようご指摘を頂いております。(超意訳すると結構試験が面倒だよって事です)  

次はCで書かれたモジュールをどのように変更・トレースするかを悩んでみます。
という大多数のJuliaユーザにはあまり興味なさそうな投稿で申し訳ない。

以上です。