糖衣がけのMoonScriptはいかが?
MoonScriptが気に入ったので、構文について色々書き散らしたいと思う。解説記事とか入門記事じゃないよ。文法知りたい人はリファレンス読みましょう。 (MoonScript v0.2.2 - Language Guide)
MoonScriptとは
Luaにコンパイルするスクリプト言語。現時点での最新バージョンは0.2.2。
MoonScriptは、JavaScriptにコンパイルするCoffeeScriptにかなり似ている。(もともとJavaScriptとLuaが似た言語だしね。)CoffeeScriptを知っていれば、MoonScriptも何となく分かると思うけど、JavaScriptとLuaの相違点が、CoffeeScriptとMoonScriptの違いに表れている。
インデントによるブロック(レイアウト)
PythonやHaskell、CoffeeScriptでお馴染みのレイアウト。最初にPythonで見たときはびっくりしたよ。色々な役割があるけど、閉じ括弧地獄が始末されるなど、色々な場面で活躍したりしなかったりします。
関数リテラル
CoffeeScript譲りの関数記法。
-- MoonScript -> f()
-- Lua function() return f() end
ただ->
とタイプするだけで関数になるので、かなり中毒性がある記法だと思う。今までいやいやfunction() return end
って打ってきてうんざりしていたところが、これだけでもう無名関数いくらでも作れるよって気になるでしょ?
括弧の省略
-- MoonScript f a, b, c f a, g b, c f a, b, g c, d, h e, f
-- Lua
f(a, b, c)
f(a, g(b, c))
f(a, b, g(c, d), h(e, f))
こんなふうに解釈される。
次のようには書けないのかな? と思ったけど、無理でした。
-- MoonScriptでは通らない -- f(a, b, c)のつもり f a b c -- f(g(a, b), h(c, d))のつもり f g a, b h c, d
! 演算子
-- MoonScript f!
-- Lua
f()
MoonScriptは関数を呼び出す際に括弧を省略できる。しかし、引数を取らない関数の場合は、何も書かないと関数自体への参照になってしまう。そんなときは!
演算子を使うと、括弧を省略できるよ!という意欲的な(?)機能。でも省略した文字数はたったの1文字なので、存在意義は微妙。好意的に取れば、引数を取らない関数ということは、何らかの副作用を期待している場合、あるいは遅延評価で値を評価させる場合だろうから、ビックリマーク(bang)を使うってのは合っている気もする。でももっといい記号の使い方を考えたほうがいい気がするなー。
テーブルリテラル
-- MoonScript scrollbar = Mx.ScrollBar adjustment: Mx.Adjustment lower: 0, upper: 10 page_increment: 1, page_size: 1
-- Lua local scrollbar = Mx.ScrollBar({ adjustment = Mx.Adjustment({ lower = 0, upper = 10, page_increment = 1, page_size = 1 }) })
括弧が省略できる。
オブジェクト指向
LuaのメソッドはJavaScriptのように、予約語this
がオブジェクトにバインドされるのではない。テーブルに格納されている関数の第一引数にテーブル自身をとることで、メソッドを実装する。
// JavaScript
obj.method(x, y, z);
-- Lua obj.method(obj, x, y, z) -- 上のシンタックスシュガー obj:method(x, y, z)
MoonScriptではシンタックスシュガーの記法が何故かコロンではなくバックスラッシュに変更されている。おそらく、コロンをテーブルリテラルに使っているため。
-- MoonScript obj\method x, y, z
Function Stubs
第一引数をテーブルにバインドした関数を、簡単に取り出せる。
-- MoonScript func = obj\method -- func(...) は obj\method(...) と同じになる
-- Lua local func = (function() local _base_0 = obj local _fn_0 = _base_0.method return function(...) return _fn_0(_base_0, ...) end end)()
ファット・アロー記法
CoffeeScriptのfat arrows記法は、this
を関数の外側のスコープのオブジェクトにバインドする記法だが、MoonScriptのfat arrows記法は単に暗黙の第一引数self
を持つ関数だ。つまり(...) =>
は(self, ...) ->
と同じ。CoffeeScriptとMoonScriptではfat arrowの意味が全く異なることに注意すること。CoffeeScriptではメソッドには->
を使うが、MoonScriptではメソッドに=>
を使うことになる。
with 式
-- MoonScript combo = with Mx.ComboBox! \append_text 'item' .index = 0 .on_notify.index = => print "selected continent: #{@active_text}"
-- Lua local combo do local _with_0 = Mx.ComboBox() _with_0:append_text('item') _with_0.index = 0 _with_0.on_notify.index = function(self) return print("selected continent: " .. tostring(self.active_text)) end combo = _with_0 end
オブジェクトを作るときなど、一つのオブジェクトに対して沢山メソッドを呼んだりプロパティを設定する時に便利。ピリオドかバックスラッシュから始まるのがプロパティやメソッドであることが明らかなので、JavaScriptのwith文のような問題は起こらないし、作ったオブジェクトをそのまま関数に渡すときは余計な変数を宣言せずに済む。
import 文
テーブルから関数やメソッドを抜き出してくる。単にlocalの変数に代入しているだけで、必要ではないが、同じ識別子を二度書かずに済む。
using 宣言
localを省略できるようになった代わりに、間違えて外側のスコープの変数に代入してしまう問題に対処するためなんだろうけど、明示的にlocalを使って書けばいいだけの気もする。スコープの問題なのに関数リテラルの括弧の中に書くのも一貫性がないし、廃止しちゃったほうがいいのでは。LiveScriptみたいに、変数の宣言と代入とで別の演算子を使うようにすればいいんじゃないかな?
欠点
動的型付け言語一般に言えるかもしれないけど、書き間違えたときが大変。そこら辺は実行時エラーメッセージから原因をエスパーする訓練が必要だと思います。
まとめ
- 括弧を減らすことで、見苦しい閉じ括弧の連続がなくなり、読みやすくなった気がする。
- シンタックスシュガーはタイプ数を減らすだけでなく、無駄な識別子を減らす働きもある。
- 全体的に好みだけどミスった時大変かも。
- MoonScriptは楽しい