プログラミング(Lua)

小ネタ(loadstring)

たとえば、C側からluaのテーブルにアクセスしたいとする。目的のテーブルはC側のみが知っているとする。

どうアクセスする?

うん、僕は機転が利かないようで、こういうことをやっていた。たとえば、a.b.cにアクセスしたいとしよう。

--C側
lua_getglobal(L,"a")--スタック=a
lua_getfield(L,-1,"b")--スタック=a a.b
lua_getfield(L,-1,"c")--スタック=a a.b a.b.c

しかもこれでcにアクセスした後は、スタックから取り除かないと残ったままになる。まぁ、ガベコレが殺してくれるだろうけど…いろいろとマンドクセなので…。イヤーンな感じだ。

ていうか直感的じゃないし、面倒だ!!こんなことやる俺が馬鹿なの?死ぬの?

なので、loadstringを使う。

--lua側
a={
b={
  c="パーフェクトフリーズ!"
}
}
function TableAccessor(tablestring)
return loadstring("return " .. tablestring)()
end

//C側
lua_pushstring(L,"a.b.c");
lua_call(L,1,1);
std::string string_of_a_b_c = lua_tostring(L,-1);

ってやればa.b.cの\アタイ/が分かるわけだ。

まぁ、自分の書いてるプログラムが、なにやら「冗長だな」って思ったり、マーチンファウラー氏の言う「やな匂い」がしたら、一度公式で正式なマニュアルなり、リファレンスなり読み直して、「なんか使える奴があるはずだ」って探すと良いと思う。このときに「何か使える奴あるかなぁ」ではダメで、「なんか使える奴があるはずだ!!」のほうがいい。luaとかC++とかの有名な言語は大抵のものはそろってるはずだから、「あるかなぁ…」じゃ見落とすことがあるからね。

| | コメント (0) | トラックバック (0)

Lua勉強法

Luaで検索で着てくれてる人が多いみたい。需要が上がってきているみたいね。日本語書籍もだいぶ出てるし。

で、僕はお金かけたくないんで、どういう勉強しているのかだけ。

ちょっとあんまし時間ないんで、ストレートに

http://sugarpot.sakura.ne.jp/yuno/html/lua51_manual_ja.html

のページをひたすら読む。読みまくる。わからんでもいいので、読みまくる。暗記するほどに読む。

で、大体わかってきたら、英語だけど頑張って
http://www.lua.org/pil/

を読む。頑張って!!

で、中身に興味が湧いてきたら、ソースコード読む。もしくは
http://www.lua.org/doc/jucs05.pdf

を頑張って読む。頑張れ!!

どうしてそこでやめちゃうんだよ!!あきらめんなよ!!もっと熱くなれよ!!お米食べろー!!

で、あきらめなかったら、いつの間にか英語も得意になってるはずなので、Luaのメーリングリストに入っておこう。

で、もう、とにかく入門書が欲しいよ。でもお金ないよって人はhttp://karetta.jp/book-cover/lua

ここにいってみよう。最近は資料が多くてすばらしいね。

| | コメント (0) | トラックバック (0)

もうここ

バレるんじゃねぇのか?と思う今日この頃。プログラマボクサーというだけで
僕を知っている大半の人には、これを書いているのが僕だとばれてしまうわなー。

で、さらに驚愕の事実。「lua 関数プログラミング」で、ググるとトップに来ちゃう。しかも二件。

…いや、今日は上司が「よし、明日はluaで関数プログラミングだ」と言ってたので、
予習で、上のワードで調べましたよ。するとこのブログですよ…マジで。俺と同じように
検索してやっちまおうてな考えだとまず確実にヒットする。

で、勧進の調べたいことがヒットしないので、

「lua lambda」で検索。すると

http://d.hatena.ne.jp/winebarrel/searchdiary?word=*%5BLUA%5D

あー、確かにプログラミングサイトですけど…なんすか~、ちょっと凄い変換…。

ちなみに昔2chで見た情報だけど、

plus = function(a)
return function(b)
  return (a+b)
end
end

print(plus(5)(6))

のように書ける。このあたりが、高階関数だとかなんとか…。確かupvalueという
関数生成時の環境をクロージャみたいにホールドするしくみがあるからこれができるらしい。

あへぇ~、よくわからんが凄いや。まぁ、クロージャの仕組みはActionScriptにも
出てくるからなじみはあるけど。僕はCとのやりとりにスタックに引数を乗せるしくみが
面白かった。まぁ低いレベルの話ですがね。たとえば、aという関数に引数1をのせて実行したい場合は

lua_pushstring(l,"a")//関数名乗っけて
lua_gettable(l,LUA_GLOBALSINDEX)//関数と入れ替えて
lua_pushnumber(l,1)//引数乗っけて
lua_call(l,1,0)//引数1個、戻り値1個で呼ぶ。

てな感じ、なんかアプリケーションの仕組みの勉強になりそうな感じで楽しい。
まぁここらへんをもうちょっといじいじといじるともうちょっと楽しいのだけれど

ただし、luaで関数プログラミングができても関数が多言語ではないため、

①関数に副作用なし
②変数なし

という制約はありません。うーん、しかしこのように記述することのうまみが今ひとつわからない。
クロージャの仕組みは有用ですよ。でもそれは関数プログラミングのおかげじゃない。クロージャのおかげ。
では関数プログラミングは何が嬉しいの?

http://www.sampou.org/haskell/article/whyfp.html

で、ここを読んでいるわけですが、読んでますますわからん。

わかったら次の機会にでも。…話変わっちゃったな。

| | コメント (0) | トラックバック (0)

LUA_REGISTRYINDEXは何のためにあるのか

ども、久しぶりのプログラムネタです。最近luaL_refを仕事でもプライベートでもよく使っているので、LUA_REGISTRYINDEXとも接する機会が多いですね。

目的としてはやっぱりポインタ代わりに使いますね。

programming in LuaのサンプルやMLでもそんなことを書いてありました。(英語なので不正確)。さて、そのprogramming in luaでのサンプルですが、

//取得
lua_pushstring(L,"関数名");
lua_rawget(L,-1);
ref = luaL_ref(L,LUA_REGISTRYINDEX);

//使用
lua_rawgeti(L,LUA_REGISTRYINDEX,ref);

//さよなら
luaL_unref(L,LUA_REGISTRYINDEX,ref);

となっていました。ここで、あれれと思ったのが、LUA_REGISTRYINDEXって何よってことです。グーグル先生で検索してもよくわかりません。

なので、自分で勝手に推測した結論は

「LUA_REGISTRYINDEXはLuaプログラムにいじられないテーブルのインデックスである」

そう、LUA_GLOBALSINDEXだと、_Gでいじれてしまうし、特定のテーブルを作ったとしてもそれを参照されては元も子もない。

一生懸命LuaからLUA_REGISTRYINDEXをいじる方法を探しましたが見つかりません。つまり、LUA_REGISTRYINDEXとはLUAからいじられたくない値だけどCからは使いたい、そういう値を登録、使用するためにあるものなのです。…だと思います。間違ってたら教えてください。

うん、ごめん。グーグル先生。ありました。5.1ではなく、5.0のマニュアルのほうに
http://uri.sakura.ne.jp/~cosmic/yuno/lab/lua5_manual_ja.html#3.18

http://sugarpot.sakura.ne.jp/yuno/html/lua51_manual_ja.html#3.5

まあ、使い方は間違っていなかったと。また認識もそれほど間違いじゃない…と

追記:

このページが、なんだかLUA_REGISTRYINDEXで検索するとTOPに来るようだ。図らずもこの結果なのだが、TOPに来る以上、不正確な記事は書けないため、「古い記事だから」と見過ごすわけにはいかなくなった。

http://sugarpot.sakura.ne.jp/yuno/html/lua51_manual_ja.html#3.5

によれば、

Luaはレジストリを提供している。これは定義済みのテーブルで、好きなLuaの値を格納するためにCのコードから使うことができる。このテーブルは常に疑似インデックス LUA_REGISTRYINDEX に置かれている。どのCのライブラリもデータを保持するためにこのテーブルを使えるが、衝突を避けるため他のライブラリが使っていないキーを選ぶ必要がある。典型的には、ライブラリ名を含む文字列とか、自分のコードで使っているCオブジェクトのアドレスを持つライトユーザーデータを、キーとして使うと良い。

レジストリ内の整数キーは、補助ライブラリで実装されているリファレンスメカニズムで使われており、それゆえ他の目的に使うべきでない。

だそうだ。また、

http://www.lua.org/pil/27.3.1.htmlを見ても、ほぼ内容は同じだと思う。

ポイントは、

①どのCのライブラリもデータを保持するためにこのテーブルを使える

ってのと、

②衝突を避けるため他のライブラリが使っていないキーを選ぶ必要がある

とある。②にさえ留意すれば好きに使っていいわけだ。

http://www.lua.org/pil/27.3.1.htmlにて、少々難解(俺にとっては)なのがこの一文

A bulletproof method is to use as key the address of a static variable in your code: The C link editor ensures that this key is unique among all libraries. To use this option, you need the function lua_pushlightuserdata, which pushes on the Lua stack a value representing a C pointer.

えーと、

防弾メソッドは、貴方のコード中の静的変数のアドレスをキーとして使用する?
Cリンクエディタは保障する→このキーは全てのライブラリでユニークであること。
このオプションを用いれば、貴方はlua_pushlightuserdata関数を必要とする、それはLuaスタックにCポインタを示す値をプッシュする。

意味分からんので、lua5.1リファレンスの解説を考慮に入れて、もうちょっと俺的意訳する。

とりあえず、"防弾メソッド"→"確実な方法"とでも訳しておく。とすると、

確実な方法のひとつは、静的変数のアドレスをキーとして使用することです。
そうするとCのリンクエディタは、そのキーが全てのライブラリにてユニークであることを保障します。
で、アドレスはつまりはポインタなわけで、lua_pushlightuserdataでLuaスタックにプッシュできるわけだ。

ああ、漸く意味が通ってきた。まぁ、そういうことだ。ここでもリファレンスとprogramming in luaは同じ事を言っている。

LUA_REGISTRYINDEXを使用するときはCオブジェクトへのアドレスをライトユーザーデータとしてプッシュして、それをキーとして使用する。

てな使い方が適切ですよ…と。多分。

| | コメント (0) | トラックバック (0)