読者です 読者をやめる 読者になる 読者になる

次は nyagos 4.2 になりそう

先日考えた Lua インスタンスをクローンする方式は、 集中してやったら、案外あっさり出来た。

foo = {
    {
        { "bar" }
    }
}

nyagos.alias.foo = function(this)
    print("foo=",foo[1][1][1])
end

こういうコードは、従来の 4.1 では foo=nil となってしまっていたのだが、最新版では foo=bar と出せるようになった。

なぜ 4.1 で期待どおり動かないかは説明しづらく、NYAGOS にとって負い目のような仕様だった。 今回の修正では ~/.nyagos で定義した shareテーブル以外のグローバル変数も、 エイリアス関数・プロンプト関数・一行入力のキー関数のいずれでも参照できるようになった。 これでほとんどの Lua ユーザが戸惑うことはなくなるだろう。

また、今まで無駄に新規 Lua インスタンスを作成していた箇所があり、それでNYAGOSの起動そのものが遅くなっていた。 今回、あくまで新規の goroutine を作った時、すなわち「foo | more」「foo &」などのように、 エイリアスをバックグラウンドで実行させたときだけ Lua インスタンスの作成・クローンを行うようにした。 このコスト削減で、Lua のクローンのコストも相殺されたのではないかと思われる。

ただ、従来の share は廃止しない。というのも、Lua インスタンスのクローンでは、 親(フォアグラウンドgoroutine)→子(バックグランドgoroutine)へと情報が伝わるだけで、 子 → 親へは伝わらないからだ。 使う機会はゼロではないが、念のため、残しておくのが無難だろう。

という感じで、かなり大胆にコードを書き替えた。 それで、安定度は下がったものの、4.1.x の負い目は払拭した。ゆえに次回は 4.2.0 か 4.2-beta というリリースになる予定だ

わたしにいい考えがある

Lua に clone 機能があればと書いていたが、実際に clone を自前で書いてしまった方が早いのでは?

  • local 変数はクロージャーの上位値の clone ができない
    • それは仕方がないと考える
  • clone した後、clone先からclone元へのフィードバックができない
    • 従来の share テーブルも併用する
    • 表向きは share を使ってくださいで、実はその他の変数も clone する
  • io やら os やらのテーブルの複写はどうするか
    • new → openlib → 自前clone の順で実行する
    • コピー先の既にオブジェクトがある場合はスキップするようにする

などなど

shareテーブルの改善

NYAGOS は各処理で別々の Lua インスタンスを作成して利用しており、~\.nyagos で定義したグローバル変数nyagosテーブル 、shareテーブルに代入されたもの以外は各処理から参照することができません。したがって、データ共有にはユーザ向けテーブルである share を通常用いるのですが、

share.git = {}
share.git.subcommand=gitsubcommands
share.git.branch = branchdetect

という使い方が出来ないという問題がありました()。これは

  • shareテーブルの各要素の実体は Go 側にある
  • shareテーブルへの代入をトリガー(__newindex)に値が、原本の方へ反映される
  • share.git.branch への代入ではトリガーが起動せず、原本の方への反映ができない

といった理由があったためです。そのため

share.git = {
    ["subcommand"]=gitsubcommands,
    ["branch"] = branchdetect,
}

あるいは

local gittmp = share.git
gittmp.subcommand=gitsubcommands
gittmp.git.branch = branchdetect
share.git =gittmp

という書き方をしなければいけませんでした。

で、今回その問題を部分的に解消しました。

具体的には、share.XXX を取り出す際にテーブルだった際、XXXLua側の複製テーブルにもトリガーを設定して、share.XXX.YYY=ZZZという代入もキャッチするようにしました。これを実現するために XXX のメタテーブルには下記の値がセットされています。

  • ["__newindex"]= 更新をキャッチする関数
  • [".."]= 自分の親となる share[] のキー文字列
  • ["age"]= share[] へ直接代入された時の回数(これが最新でなかったら share[] には別の値が既に代入されている)

ただ、この方式だと share.WWW.XXX.YYY = ZZZ という、さらに深い階層での代入までキャッチできません。 次のようなことを考えると、あまり完璧実装しても益が少ないだろうと思っての手抜き実装であるためです。

  • ここまで深い階層を一度に取り扱うのは逆に書きづらいからユーザもやらないだろう
  • 将来的に他の組込言語をサポートし、Lua 依存性を下げるため、ここであまり完璧なものを仕上げても意味がないかもしれない

あと、Luaインスタンスですが、マルチスレッド環境で用いるとパニックの原因となるため、極力細かく別のインスタンスを用意していました。 が、分離しなくてもいいところまで分離していたところがありますので、これも可能な範囲で統合して、share テーブルを意識しないでよい方向へ持っていきたいと考えています。

今のところ、別インスタンスになっていたプロンプト関数(nyagos.prompt)を、.nyagos読み取りのインスタンスと同じにしました。 あと一行入力内・補完も本来は同じインスタンスでいけるはずなので、現在、調査・検討中です。

しかし、面倒くさい話です。Lua インスタンスがクローンできたら、こんな苦労はないのですが。もっと言えば、UNIXだったらプロセスごとクローンできるのですが。 やはり、C言語ではなく、Go言語で作成された組み込み言語を使いたいものです。

いや、自分の設計が悪いのをツールの責任にしてはいけませんね。

Goで、そのうち使ってみたいライブラリ・ツールリスト

mastodon ここ最近、ちょっと触っているので(頭痛をまぎらわしがてら)所感を

  • jpサーバは中学生・高校生みたいな下品な投稿が多くて、ローカルタイムラインは見てられないが、著名な技術者も泳いでいるので、外せない。でも、別に他のサーバにアカウントを作っても、リモートでフォローできるのが mastodon のよいところだから、jpサーバーにこだわる必要はない
  • Go言語製のコマンドラインクライアント(go-mastodon)の開発に「ちょっとだけ」携われて楽しかった(2,3 Pull Request 送っただけ)
  • 500文字もあると、タンブラー的に使えてよい。また、文書が長い時「(続きを読む)」で本文を隠せるようになったのは地味に便利。読み手の利便性を意識した書き方ができる
  • 共有のためのブックマークレットがないのがちょっと不便。とりあえず、コピペ支援の簡単なブックマークレット※で代用中
  • 前身の GNU Social(quitter.noとか)の時は日本人がほとんどいなくて寂しかったが、mastodon は賑やかで本当に嬉しい。これで、仕様変更でユーザを振り回す twitter 社の呪縛から逃れられる

javascript:(function(){var v=window.getSelection();prompt('',(v==''?'':'『'+v+'』\n')+'QT ' + document.title + ' ' + window.location.href)}())

C:\path\\to は invalid なパスか、否か?

IPAのページ Windowsパス名の落とし穴によると

4. d:\\InetPub\\\wwwroot\\\\secret\\\\\data.txt
    ディレクトリの区切り文字は幾つか重複しても構わない

とあるため、これを信じると C:\path\\to は Valid なパスである。

無論、これイコール Microsoft の見解というわけではないが、 .NET Framework の System.IO.File.Exist 関数や、 System.IO.Directory.Exist 関数でも True が戻ってくるため、 Microsoft の指針と矛盾しないと考えるのが妥当だろう。

だが、Windowsエクスプローラーのパス入力欄に入力すると

'C:\path\\to' は見つかりません。綴りを確認して再実行してください。

などとエラーにされる。

ユーザからすると、こちらが目に入りやすいため、 「\\というパス区切りをエラーにしないとはどういうことか」 ということになる。

困ったものですなぁ

☭(U+262D)のコマンドプロンプトに置ける文字の幅問題

☭という記号がある。「鎌と槌」(HAMMER AND SICKLE)と呼ばれる記号で、いわゆる共産党のシンボルである。

この文字、East_Asian_Width は Neutral になっているWikipediaの東アジアの文字幅によると

UAX#11では、これらの特性を次のように解釈することを推奨している。

Unicode のテキストを東アジアの従来文字コードの文脈で扱う場合
- 特性値Na(狭)またはN(中立)を持つ文字は、半角の文字 (halfwidth) として扱う
  :
Unicode のテキストを東アジア以外の従来文字コードの文脈で扱う場合
- 特性値Na(狭)またはN(中立)を持つ文字は、幅の狭い文字 (narrow) として扱う。

であるため、規格上はいわゆる「半角文字」である。

が、コマンドプロンプトで実際に出力すると、セルを二つ消費する。つまり、「全角文字」相当になっている。

これが原因で go-runewidth をそのまま使って、文字の桁数を計算することができなくなっている。仕方がないので、実際にコマンドプロンプトに出力した時のカーソル移動量で文字の桁数を求めている。

NYAGOS の一行入力パッケージでは、極力 go-colorable によるエスケープシーケンスだけで処理を済まそうとしているが、一部どうしてもコンソールの API を直接呼び出している。この文字桁問題がなければ、ひとつ直接呼出しが減らせるんだけどな…