Lua SBLP 2001 招待論文

第5回ブラジルプログラミング言語シンポジウム論文集 (2001) B-14–B-28 からの再版。[ps]

拡張言語の進化:Luaの歴史

Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes 著

概要

1993年の創設以来、Luaプログラミング言語は私たちの最も楽観的な期待をはるかに超えて発展しました。本稿では、2つの特定のプロジェクトのための社内言語としての作成から、2000年11月にリリースされたLua 4.0までのLuaの軌跡を説明します。その概念の進化と実装における主要なランドマークについて議論します。

はじめに

「ラクダは委員会によって設計された馬である」という古いジョークがあります。プログラミング言語の人々の間では、このジョークは、委員会によって設計されたプログラミング言語に関する伝説と同じくらい人気があります。この伝説は、委員会によって設計され、スポンサーの期待に応えられなかったAlgol 68、PL/I、Adaなどの言語によって裏付けられています。

しかし、委員会とは別に、これらの言語の部分的な失敗には別の理論があります。それらはすべて、大規模になるために生まれたということです。それらはすべてトップダウンの設計プロセスに従っており、言語は、プログラマーが試すことができるようになる前、コンパイラが構築される前でさえ、完全に仕様が定められていました。

一方、ほとんどの成功した言語は、設計されるのではなく、育てられます。それらはボトムアップのプロセスに従い、通常は控えめな目標を持つ小さな言語として始まります。人々が言語を使用し始めると、設計上の欠陥が表面化し、新しい機能が追加され(または、最終的には削除され)、議論の余地のある点が明確化(または、最終的には不明確化)されます。したがって、言語が進化する方法は、プログラミング言語における重要な研究トピックです。たとえば、SIGPLANはすでにプログラミング言語の歴史に関する2つの会議を主催しています [31,3]。

本稿では、Luaプログラミング言語の歴史について報告します。2つの特定のプロジェクトのための社内言語としての創設以来、Luaは私たちの最も楽観的な期待をはるかに超えて発展しました。この成功の主な理由は、元の設計上の決定、つまり、言語をシンプルで小さく保つこと、実装をシンプル、小型、高速、ポータブル、そして無料に保つことにあると考えています。

Luaは、委員会によって(あるいは、より正確には育てられて)設計されました。メンバーはわずか3人の小さな委員会ですが、委員会です。後から考えると、小さな委員会によって育てられたことは、言語にとって非常に良かったと考えています。新しい機能は、全員一致に達した場合にのみ追加します。そうでない場合は、将来のために残されます。機能を削除するよりも、後で追加する方がはるかに簡単です。この開発プロセスは、言語をシンプルに保つ上で不可欠であり、シンプルさは私たちの最も重要な資産です。Luaのその他の品質、つまり速度、小型サイズ、ポータビリティは、そのシンプルさから派生しています。

Luaは最初のバージョンから「本物」のユーザー、つまり私たち以外のユーザーを持っていました。彼らは常に、提案、苦情、使用レポート、質問を通じて、言語に重要な貢献をしてくれました。ここでも、私たちの小さな委員会は重要な役割を果たします。その構造は、ユーザーのすべての提案に従わずに、ユーザーの声に耳を傾けることができるだけの慣性を提供してくれます。

本稿の残りの部分は、時系列順に構成しています。1993年のLuaの作成につながった過去の経験から始め、8年間の議論、決定、作業、そして楽しみを続けます。

始まり

TeCGrafでの社内設計の言語の最初の経験は、データ入力アプリケーションで生まれました。PETROBRAS(ブラジルの石油会社)のエンジニアは、シミュレーターの入力データファイルを1日に何度も準備する必要がありました。シミュレーションプログラムは、各数値が何を意味するのかを示さない、典型的な裸の数値の列など、厳密にフォーマットされた入力ファイルを必要とするレガシーコードであったため、このプロセスは退屈でエラーが発生しやすいものでした。もちろん、各数値には特定の意味があり、エンジニアは特定のシミュレーションのを見れば一目で把握できました。TeCGrafはPETROBRASから、この種のデータ入力用のグラフィカルなフロントエンドをいくつか作成するように依頼されました。その後、図の関連部分をクリックするだけで、インタラクティブに数値を入力できるようになり、数値の列を編集するよりもはるかに簡単で意味のある作業になりました。さらに、データの検証を追加し、入力データから派生した量を計算する機会が開かれ、ユーザーから必要なデータの量が削減され、プロセス全体の信頼性が向上しました。

TeCGrafでのこれらのフロントエンドの開発を簡素化するために、すべてを均一な方法でコーディングすることに決め、各データ入力タスクを記述するための単純な宣言型言語を設計しました [12]。以下は、DEL(データ入力言語)と呼ばれるこの言語の典型的なプログラムの一部です。

   :e      gasket            "gasket properties"
   mat     s                  # material
   m       f       0          # factor m
   y       f       0          # settlement stress
   t       i       1          # facing type

   :p
   gasket.m>30
   gasket.m<3000
   gasket.y>335.8
   gasket.y<2576.8
ステートメント:eは、エンティティ(gasketと、例では呼ばれる)を定義します。これは、デフォルト値を持ついくつかのフィールドがあります。ステートメント:pは、gasketの値に対するいくつかの制限を定義し、データ検証を実装します。DELには、データの入出力方法を指定するステートメントもありました。

DELのエンティティは、従来のプログラミング言語における構造体またはレコードと本質的に同じです。違いは、その名前が、前述のように、エンジニアがデータ入力を行う関連図を含むグラフィカルなメタファイルにも表示されることです。

この単純な言語は、TeCGrafでの開発を簡素化したためと、ユーザーがデータ入力アプリケーションを調整するのが簡単だったため、TeCGrafとユーザーの両方で成功しました。すぐにユーザーはDELからより多くのパワーを要求し始めました。たとえば、エンティティが入力に対してアクティブかどうかを制御するためのブール式などです。そしてDELはより重くなりました。ユーザーが条件付き制御とループを要求し始めたとき、真のプログラミング言語が必要であることは明らかでした。

ほぼ同時期に、PETROBRASの別のプロジェクトであるPGM(リソロジープロファイルの構成可能なレポートジェネレーター)の作業を開始しました。名前が示すように、このプログラムによって生成されるレポートは高度に構成可能です。ユーザーはトラックを作成して配置し、色、フォント、テキストを選択できます。各トラックにはグリッドがあり、それにもオプションのセットがあります(対数/線形、垂直および水平ティックなど)。各カーブには独自のスケールがあり、オーバーフローが発生した場合は自動的に変更する必要があります。など。

この構成はすべて、通常は地質学者またはエンジニアであるエンドユーザーによって行われる必要があり、プログラムはMS-DOSを実行するPCなどの小型マシンで実行する必要がありました。このアプリケーションを構成する最適な方法は、Solと呼ばれる特殊な記述言語を使用することであると判断しました。Solは、Simple Object Languageの頭字語であり、ポルトガル語で太陽も意味します。

レポートジェネレーターには多くの異なるオブジェクトがあり、それぞれに多くの異なる属性があったため、言語でそれらのオブジェクトと属性を固定しませんでした。代わりに、言語は型宣言を許可しました。インタプリタの主なタスクは、記述を読み取り、指定されたオブジェクトと属性が正しく型付けされているかどうかを確認し、その情報をメインプログラムに提示することでした。メインプログラムとインタプリタ間のこの通信を可能にするために、後者はメインプログラムにリンクされたCライブラリとして実装されました。したがって、メインプログラムはこのライブラリのAPIを介してすべての構成情報にアクセスできます。さらに、プログラムは型ごとにコールバック関数を登録できるため、インタプリタは指定された型のオブジェクトを作成するたびにこの関数を呼び出します。

次のチャンクは、Solの典型的なコードを示しています。

   -- defines a type `track', with numeric attributes `x' and `y',
   -- plus an untyped attribute `z'. `y' and `z' have default values.
   type @track { x:number,y:number= 23, z=0}

   -- defines a type `line', with attributes `t' (a track),
   -- and `z', a list of numbers.
   -- `t' has as default value a track with x=8, y=23, and z=0.
   type @line { t:@track=@track{x=8},z:number*}

   -- creates an object `t1', of type `track'
   t1 = @track { y = 9, x = 10, z="hi!"}

   -- creates a line `l', with t=@track{x=9, y=10},
   -- and z=[2,3,4] (a list)
   l = @line { t= @track{x=t1.y, y=t1.x}, z=[2,3,4] }
Solの構文は、BiBTeX [21] と、Motif [24] でユーザーインターフェイスを記述するための言語であるUIL(User Interface Language)の影響を強く受けていました。

1993年3月にSol言語の最初の実装を完了しましたが、提供することはありませんでした。1993年半ばまでに、DELとSolの両方を単一の、より強力な言語に結合できることに気づきました。リソロジープロファイルを視覚化するためのプログラムは、より洗練されたレイアウトを作成するために手続き型プログラミングのサポートをすぐに必要とするでしょう。一方、データ入力プログラムも、ユーザーインターフェイスをプログラミングするための記述的な機能が必要でした。

そこで、代入、制御構造、サブルーチンなどを備えた、真のプログラミング言語が必要であると判断しました。言語は、Solによって提供されるようなデータ記述機能も提供する必要があります。さらに、言語の潜在的なユーザーの多くはプロのプログラマーではなかったため、言語は暗号のような構文(およびセマンティクス)を避ける必要があります。最後に、新しい言語の実装は高度に移植可能である必要があります。

移植性の要件は、その主な強みの1つであることが判明しました。これら2つのアプリケーションは完全に移植可能である必要があり、言語も同様である必要がありました。国営のPETROBRASは、公費支出に関する非常に厳格な規則の下でしか機器を購入できなかったため、特定のハードウェアを選択することができませんでした。したがって、PETROBRASは非常に多様なコンピューターコレクションを持っており、そのため、TeCGrafでPETROBRAS向けに開発されたソフトウェアは、PC DOS、Windows(当時3.1)、Macintosh、およびすべてのフレーバーのUnixを含む、それらが持っているすべてのマシンで実行する必要がありました。

その時点で、新しい言語を作成する代わりに、既存の言語を採用することができました。主な候補はTcl [25] であり、それに大きく遅れてForth [26] とPerl [30] がありました。Perlは拡張言語ではありません。1993年には、TclとPerlはUnixプラットフォームでのみ実行されました。3つすべてに、非常に暗号のような構文があります。また、どれもデータ記述の優れたサポートを提供していません。そこで、新しい言語の開発を開始しました。

すぐに、私たちの目的では、言語に型宣言が必要ないことに気づきました。代わりに、言語が基本的な反射機能(ランタイム型情報など)を提供している場合、言語自体を使用して型チェックルーチンを記述できます。次のような代入

   t1 = @track {y = 9, x = 10, z="hi!"}
これはSolでは有効でしたが、新しい言語でも有効ですが、意味は異なります。これは、指定されたフィールドを持つオブジェクト(つまり、連想テーブル)を作成し、関数trackを呼び出してオブジェクトを検証します(最終的にはデフォルト値を提供するため)。

新しい言語はSol(太陽)の修正版だったので、TeCGrafの友人はLua(ポルトガル語で)という名前を提案し、Luaが誕生しました。

LuaはSolからレコードとリストの構成の構文を継承しましたが、連想テーブルを使用してそれらの実装を統一しました。レコードは文字列(フィールド名)をインデックスとして使用します。リストは整数を使用します。これらのデータ記述機能とは別に、Luaには新しい概念はありませんでした。単に軽量な汎用言語が必要でした。したがって、Modula(while, if、およびrepeat until

)から借用した構文を使用して、小さな制御構造のセットに落ち着きました。 ). CLUからは、多重代入と関数呼び出しからの多重戻り値(in-outパラメータや参照パラメータよりもはるかに明確な概念)を取り入れました。C++からは、ローカル変数を必要な場所でのみ宣言できるという素晴らしいアイデアを取り入れました。

数少ない(どちらかといえば小さな)革新の1つは、文字列連結の構文でした。言語では文字列から数値への型変換が許可されているため、+記号は曖昧になります。そこで、その操作には..(ドット2つ)という構文を作成しました。

論争の的となったのはセミコロンの使用についてでした。セミコロンを必須にすると、FORTRANの経験を持つエンジニアには少し混乱を招く可能性があると考えましたが、許可しないとCやPascalの経験を持つ人が混乱する可能性がありました。最終的に、オプションのセミコロン(典型的な委員会による解決策)に落ち着きました。

当初、Lua言語には7つの型がありました。数値(浮動小数点数として実装)、文字列、(連想)テーブル、nil(nilという固有の値を持つ型)、userdata(Lua内部でC構造を表すための汎用Cポインタ)、Lua関数、およびC関数です。(8年間の継続的な進化の後、Luaの型における唯一の変更点は、Lua関数とC関数が単一の関数型に統合されたことです。)言語を小さく保つために、ブール型は含めませんでした。Lispと同様に、nilはfalseを表し、その他の値はtrueを表します。これは、今日時々後悔する数少ない倹約の1つです。

Luaはまた、Solからライブラリとして実装されるという概念を受け継ぎました。実装は、現在エクストリームプログラミングで支持されている原則「最も単純で機能する可能性のあるもの」[1]に従いました。私たちはlexをスキャナーに使用し、yaccをパーサーに使用しました。パーサーはプログラムをバイトコード形式に変換し、その後、単純なスタックベースのインタープリターによって実行されました。言語には、Cで新しい関数を追加するのが簡単だったため、非常に小さな事前定義済みライブラリがありました。

この単純な実装にもかかわらず、あるいはそれゆえに、Luaは私たちの期待を上回りました。PGMプロジェクトとデータ入力(ED)プロジェクトの両方でLuaがうまく使用されました[16](PGMは現在も使用されています)。すぐに、TeCGraf内の他のプロジェクトもLuaを使用し始めました。

初期(1994〜1996年)

新しいユーザーは新しい需要を生み出します。驚くべきことではありませんが、Luaに対する最初の要求の1つは、パフォーマンスの向上でした。データ記述にLuaを使用することは、一般的なスクリプト言語にとって通常ではない課題を提起しました。

Luaを使い始めるとすぐに、グラフィックメタファイルのサポート言語としての潜在的な使用法を特定しました。Luaのデータ記述機能により、グラフィック形式として使用できます。他のプログラム可能なメタファイルと比較して、Luaメタファイルには、真のプロシージャル言語に基づいているという利点があります。たとえば、VRML形式では、JavaScriptを使用してプロシージャルオブジェクトをモデル化しているため、異種(したがって不潔な)コード[2]になります。Luaを使用すると、プロシージャルオブジェクトをシーン記述に組み込むのが自然になります。プロシージャルコードフラグメントを宣言ステートメントと組み合わせて、複雑なオブジェクトをモデル化し、明瞭さを維持できます。

データ入力プログラム(ED)は、グラフィックメタファイルにLuaを最初に使用したプログラムでした。ダイアグラムが数千個のパーツで構成され、Luaコンストラクターで数千個のアイテムが記述され、ファイルが数百Kバイトになることは珍しくありませんでした。これは、Luaがプログラミング言語の観点から、巨大なプログラムと巨大な式に対応する必要があったことを意味します。また、Luaはそのようなプログラムをオンザフライでプリコンパイルしたため(「ジャストインタイムコンパイラー」)、Luaコンパイラーも非常に高速である必要がありました。このパフォーマンスの追求における最初の犠牲者はlexでした。によって生成されたスキャナーをlex手書きのものに置き換えると、Luaコンパイラーの速度がほぼ2倍になりました。

また、コンストラクター用に新しいオペコードを作成しました。次のようなリストコンストラクターの元のコードは

   @[30, 40, 50]
次のようになっていました。
   CREATETABLE
   PUSHNUMBER 1                 # index
   PUSHNUMBER 30                # value
   SETTABLE
   PUSHNUMBER 2                 # index
   PUSHNUMBER 40                # value
   SETTABLE
   PUSHNUMBER 3                 # index
   PUSHNUMBER 50                # value
   SETTABLE
新しいスキームでは、コードは次のようになります。
   CREATETABLE
   PUSHNUMBER 30                # value
   PUSHNUMBER 40                # value
   PUSHNUMBER 50                # value
   SETTABLE 1 3                 # set elements from index 1 to 3
長いコンストラクターの場合、すべての要素を保存する前にスタックにプッシュすることは不可能でした。そのため、コードジェネレーターはSETTABLE命令を時々発行して、スタックをフラッシュしました。

(それ以来、私たちは常にコンパイル時間の改善を試みてきました。現在、Luaは、30000の代入を含むプログラムを、Perlよりも6倍速く、Pythonよりも8倍速くコンパイルします。)

1994年7月、これらの最適化を施したLuaの新バージョンLua 1.1[19]をリリースしました。このバージョンは、ftpでダウンロードできるようになりました。以前のバージョンは、公開されなかったため、Lua 1.0という名前になりました。その頃、私たちはLuaを説明する最初の論文も発表しました[10]。

Lua 1.1には、制限的なユーザーライセンスがありました。学術用途には無料でしたが、商業用途には無料ではありませんでした。(ライセンスにもかかわらず、常にオープンソースでした。)しかし、そのライセンスは機能しませんでした。PerlやTclなどのほとんどの競合他社は無料でした。さらに、商業的な制限は、最終的に市場に出ることを計画しているいくつかの学術プロジェクトとして、学術的な用途でさえも妨げます。そのため、私たちは次のバージョンの言語Lua 2.1をフリーソフトウェアとしてリリースしました。

Luaバージョン2

Lua 2.1(1995年2月リリース)は、多くの重要な変更をもたらしました。その1つは言語自体ではなく、言語開発のプロセスにありました。以前のバージョンとの小さな非互換性を犠牲にしても、常に言語の改善を試みるべきだと判断しました。

バージョン2.1では、実際にバージョン1.1との大きな非互換性を導入しましたが(変換を支援するツールを提供しました)、コンストラクターから@を削除し、レコードとリストの両方に中かっこを使用することを統一しました。@を削除するのは些細な変更ですが、実際には、単に見た目だけでなく、言語の雰囲気も変えました。

さらに重要なことに、コンストラクターのセマンティクスを簡略化しました。Lua 1.1では、式@track{x=1, y=10}には特別な意味がありました。Lua 2.1では、式track{x=1, y=10}は、track({x=1, y=10})の単なる構文糖衣です。つまり、新しいテーブルを作成し、それを関数trackへの唯一の引数として渡します。

当初から、Luaは拡張言語として設計しました。つまり、CプログラムはLuaから透過的に呼び出される独自の関数を登録できます。このようにして、ドメイン固有のプリミティブでLuaを簡単に拡張できるため、エンドユーザーは自分のニーズに合わせた言語を使用できます。

バージョン2.1では、フォールバックの概念を導入しました。これは、Luaが続行方法を把握していないときに呼び出されるユーザー定義関数です。Luaは、一連の「プリミティブ」関数を拡張することと、フォールバックでセマンティクスを拡張することの2つの方法で拡張できる言語になりました。これが、私たちがLuaを拡張可能な拡張言語と呼ぶ理由です。

算術、比較、文字列連結、テーブルアクセスなどのフォールバックを定義しました。ユーザーが設定すると、これらの操作のオペランドが必要な型でない場合、対応するフォールバック関数が呼び出され、その戻り値が加算の結果として使用されます。たとえば、2つの値が加算され、そのうちの1つが数値でない場合は、フォールバックが呼び出され、その戻り値が加算の結果として使用されます。

特に興味深いのは、テーブルアクセスのフォールバックであり、実際にフォールバックを導入する主な理由です。ステートメントx=a[i]では、a[i]がnilの場合、フォールバックが呼び出され(設定されている場合)、その戻り値がa[i]の値として使用されます。この単純な新機能により、プログラマーはテーブルアクセスに対して異なるセマンティクスを実装できるようになりました。特に、いくつかの種類の継承を実装でき、最も単純なものは委譲による単一継承です。

   function Index (a,i)
     if i == "parent" then       - to avoid loop
       return nil
     end
     local p = a.parent
     if type(p) == "table" then
       return p[i]               - may trigger Index again
     else
       return nil
     end
   end

   setfallback("index", Index)

このコードは、テーブルに必要なフィールドがあるか、チェーンが終了するまで、「親」のチェーンを上にたどります。「index」フォールバックが上記のように設定されている場合、以下のコードは、bcolorフィールドがない場合でもredを出力します。

   a=Window{x=100, y=200, color="red"}
   b=Window{x=300, y=400, parent=a}
   print(b.color)

「親」フィールドを介した委譲について、魔法のような、または「ハードコード化」されたものはありません。これはプログラマーの選択です。彼女は「親」フィールドに別の名前を使用したり、「親」フィールド自体を順に試行される親のテーブルにすることで、より複雑な多重継承を実装したり、他の何かを実装したりできます。

aがテーブルでない場合、式a[i]に対して異なるフォールバックが呼び出されました。x=a[i]のようにa[i]の値を取得するためにトリガーされる「gettable」フォールバックと、a[i]=xのようにa[i]の値を設定するためにトリガーされる「settable」フォールバックがありました。

これらのテーブルフォールバックを利用する可能性はたくさんあります。クロスランゲージ継承は非常に強力なものです。aがuserdata値(ホストCプログラムのポインター)の場合、テーブルフォールバックは、プログラマーがホストプログラムに存在するデータ構造の値に透過的にアクセスできるようにします。

これらの可能な動作をハードコードしないという私たちの決定は、Luaの主な設計概念の1つであるメタメカニズムにつながりました。言語に多くの機能を追加するのではなく、ユーザーが自分自身で必要な方法で、また、必要な機能のみに対して機能をプログラムできる方法を提供しました。

フォールバックメタメカニズムにより、Luaはオブジェクト指向プログラミングをサポートできるようになりました。つまり、(いくつかの種類の)継承(および演算子オーバーロード)を実装できます。私たちは、「メソッド」を定義および使用するための構文糖衣を追加しました。関数はa:f(x,y,z)として定義でき、a.fにはselfと呼ばれる非表示のパラメーターが追加されます。つまり、a:f(10,20,30)の呼び出しはa.f(a,10,20,30)と同等です。

1996年5月、私たちはLua 2.4をリリースしました。この新しいバージョンの主な機能は、外部コンパイラーでした。luacと呼ばれます。このプログラムは、Luaコードをプリコンパイルし、バイトコードと文字列テーブルをバイナリファイルに保存します。このファイルの形式は、簡単にロードでき、異なるプラットフォーム間で移植できるように選択されました。luacを使用すると、luacプログラムは、特にグラフィックメタファイルなどの大規模で静的なプログラムの場合、実行時の解析とコード生成を回避できます。これはコストがかかる可能性があります。

Luaに関する最初の論文[10]では、すでに外部コンパイラーの可能性を予測していましたが、TeCGrafでLuaが広く使用されるようになり、グラフィックエディターの出力としてLuaで大規模なグラフィックメタファイルが作成された後にのみ必要になりました。

ロード時間の短縮に加えて、luacluacでは、オフライン構文チェックとユーザーによる変更からのソースコードの保護も可能です。ただし、プリコンパイルは実行速度の向上を意味しません。Luaチャンクは常に実行前にバイトコードにコンパイルされるためです–luacluacは、それらのバイトコードを後で実行するためにファイルに保存できるようにするだけです。

luacは「クライアントモード」で実装されています。つまり、Luaを実装するモジュールを(礼儀正しい)クライアントとして使用しています。ただし、保存する必要がある内部データ構造にアクセスするためにプライベートヘッダーファイルを含めています。このポリシーの利点の1つは、Luaのコアの実装を明確に分離されたモジュールに構造化するのに役立ったことです。特に、Lua 4.0のコアコードの40%を占める解析モジュール(字句解析器、パーサー、およびコードジェネレーター)を簡単に削除でき、プリコンパイルされたチャンクをロードする小さなモジュールだけを残すことができます。これは、モバイルデバイスやロボット(2000年と2001年にデンマークで開催されたロボカップで優勝したロボット「クレイジー・イワン」には、Luaで実装された「脳」があります)などの小型デバイスに組み込むためのLuaの小型実装に役立ちます。

国際的な展開(1996年~2000年)

1996年6月、私たちはSoftware: Practice & Experience誌にLuaに関する学術論文を発表しました[18]。1996年12月、Dr. Dobb's誌がLuaに関する記事を掲載しました[11]。これらの異なるコミュニティを対象とした出版物により、Luaは国際的に知られるようになりました。

Dr. Dobb'sの記事の後すぐに、Luaに関するいくつかのメッセージを受け取りました。最初のメッセージの1つは次のとおりでした。

   From: Bret Mogilefsky <mogul@lucasarts.com>
   To: "'lua@icad.puc-rio.br'" <lua@icad.puc-rio.br>
   Subject: LUA rocks!  Question, too.
   Date: Thu, 9 Jan 1997 13:21:41 -0800

   Hi there...

   After reading the Dr. Dobbs article on Lua I was very eager to check it
   out, and so far it has exceeded my expectations in every way!  It's
   elegance and simplicity astound me.  Congratulations on developing such
   a well-thought out language.

   Some background: I am working on an adventure game for the LucasArts
   Entertainment Co., and I want to try replacing our older adventure game
   scripting language, SCUMM, with Lua.

   [...]
ブレット・モギレフスキーは、1997年にルーカスアーツがリリースしたメインアドベンチャーゲーム「Grim Fandango」のリードプログラマーであることが判明しました。別のメッセージで彼は、「このゲームの途方もない量がLuaで書かれている」(彼の強調)と述べました。ゲームでのLuaのこの最初の使用は、世界中の多くのゲーム開発者の注目を言語に集めました。その後すぐに、Luaは次のようなゲームニュースグループによく登場するようになりました。rec.games.programmerおよびcomp.ai.games.

Luaは、その小さなサイズ、優れたパフォーマンス、移植性、および統合の容易さから、ゲームを拡張するための言語として大きな人気を博しています。今日では、いくつかのゲーム会社(例:LucasArts、BioWare、Slingshot Game Technology、およびLoewen Entertainment)がLuaを使用しており、Luaの知識はゲーム業界で市場価値のあるスキルです。Luaユーザーの半分は、何らかの形でゲームプログラミングに関わっていると推定していますが、ゲーム業界には多くの秘密があるので、さらに特定するのは困難です。たとえば、ブレット・モギレフスキーは「Grim Fandango」のためにLuaを適応させましたが、詳細はもちろん独占的でした。

スクリプト言語をゲームに埋め込むことには、いくつかの利点があります。スクリプト言語は、スプライトとオブジェクトの物理学の定義、オブジェクトAIとキャラクターコントロールの管理、および入力デバイスイベントの処理に使用できます。たとえば、エンジンは「ダメージ」、「スピード」、「武器」などのことについて何も知らない場合があります。シンプルな言語を選択することで、ゲームデザイナーはプログラマブルツールにアクセスすることもできます。これは、デザイナーが自分の作品を試すことができるため、ゲーム開発にとって非常に重要です。スクリプト言語は、迅速なプロトタイピングを可能にし、デバッガーツールの実装を容易にします。

最近では、2000年にルーカスアーツはLuaを使用する別のゲームをリリースしました。「Escape from Monkey Island」は、モンキーアイランドシリーズのアドベンチャーの4作目でした。このゲームでは、Luaへのオマージュとして、ゲーム内のバーを、以前使用していた言語であるSCUMMからLuaバーに名前を変更しました。

コンピュータゲーム(例:「Grim Fandango」、「Baldur's Gate」、「MDK2」、「Escape from Monkey Island」)での幅広い使用に加えて、Luaは世界中のさまざまな分野で使用されてきました。

PUC-Rio以外でのLuaの最初の使用例の1つは、スミソニアン天体物理観測所でした。彼らは、物理的な障害物が入射光子ストリームに与える影響をシミュレートするための汎用的な開口プログラムを設計し、Luaを使用して、入射光子ストリームと開口部の幾何学的形状と相互作用をモデル化しました[23]。このプログラムは、NASAの4つのグレートスペースオブザーバトリーの3番目であるAXAFプログラム(高度X線天体物理施設)をサポートするための取り組みの一部でした。

Performance Technologiesは、ホットスワップ可能なイーサネットスイッチであるCPC4400のコマンドラインインターフェースを実装するためにLuaを使用しました。CPC4400のスクリプト言語としてLuaを公開することにより、ユーザーはイベント(リンクステータス、トポロジ変更の検出、RMONアラームなど)をLuaスクリプトに関連付けることができます。

Tollgrade Communicationsは、次世代の電話ネットワークテスト製品であるDigiTestでLuaを使用しました。Luaは、ユーザーインターフェース、自動テストスクリプト、および結果分析に使用されました。

Luaは、ブラジルのInCor心臓研究所(Instituto do Coração、サンパウロ)でも使用されています。同じくブラジルのCEPEL(国営電力会社ELETROBRASの研究センター)、ベルリンのワイエルシュトラス研究所、ベルリン工科大学、その他多くの場所でも使用されています。

1998年、キャメロン・レアードとキャスリン・ソライズは、SunWorld誌のスクリプト言語に関するコラムで、「世界には数万人のLuaプログラマーしかいないかもしれない」と推定しました[20]。彼らが「小さなユーザーベース」と見なしたものは、私たちにとっては言語の人気が高まっていることを示す強い兆候でした。

Luaバージョン3

Lua 3.0(1997年7月)では、フォールバックがより強力なタグメソッドの概念に置き換えられました。フォールバックは本質的にグローバルでした。イベントが発生するたびにユーザー関数が呼び出され、イベントごとに1つの関数しかありませんでした。これにより、たとえば、異なる継承概念を持つLuaモジュールを組み合わせることが困難になりました。フォールバックを連鎖させることは可能でしたが、連鎖は遅く、エラーが発生しやすく、実際には誰も行いませんでした。

Lua 3.0以降、プログラマーはタグを作成し、テーブルとユーザーデータをタグに関連付けることができます。タグメソッドは、基本的にオペレーターのタグに応じて選択されるフォールバックです。タグとタグメソッドを使用すると、異なるテーブル(およびユーザーデータ)は、その操作に対して異なるフォールバックを持つことができます。

タグの概念は、基本的にLuaにユーザー定義の型を提供します。言い換えれば、タグは単に新しい型を表す数値です。テーブルを特定のタグに関連付けると、実際にはそのテーブルの新しい型を定義することになります。テーブルの型(またはタグ)は、テーブルがどのように演算子を実装するかを指定します。

フォールバックを導入したとき、それらのほとんどは、テーブル以外の値をインデックス付けしたり、関数以外の値を呼び出したりするなど、それ以外の場合はエラーが発生するイベントに対するLuaの動作を記述していました。したがって、フォールバックを例外処理メカニズムとして考えました。ユーザー定義のタグの導入により、フォールバック(現在はタグメソッドと呼ばれます)は、基本的な型の動作を拡張するために使用できるにもかかわらず、主に新しい型の動作を記述するためのメカニズムになりました。

この新しいステータスにもかかわらず、長い間、タグメソッドを例外処理メカニズムとして認識し、タグと型を結び付けませんでした。最近になって、ユーザー定義のタグとタグメソッドを、ユーザー定義の型を作成するためのメカニズムとして完全に認識するようになりました。Lua 4.1では、ユーザーがこれらの新しい型に名前を提供できるようにすることで、この認識を確固たるものにします(現在、基本型のみが名前を持っています)。

Lua 3.0では、Cのようなプリプロセッサの形で、条件付きコンパイルのサポートも導入されました。他の言語機能と同様に、追加するのが簡単すぎましたが(ただし、字句解析器が複雑になりました)、すぐにプログラマーが使い始めました(プログラマーはあらゆる言語機能を使用します)。一度機能が使用され始めると、より多くのパワーに対する要求がすぐに起こります。最も頻繁な要求の1つはマクロ展開の追加でしたが、メーリングリストと私たち自身の長い議論の中で明確な提案は出てきませんでした。そのような提案はすべて、字句解析器とパーサーの大幅な変更を意味し、利点は明確ではありませんでした。そのため、プリプロセッサはLua 3.0からバージョン3.2(2年間)まで静的なままでした。

最終的に、プリプロセッサは良いことよりも害をもたらし、コードをかさばらせ、ユーザーからの終わりのない議論を招いていると判断し、Lua 4.0で削除しました。プリプロセッサがない方がLuaはきれいになったと感じています。長年にわたり、私たちはLuaをよりシンプルにするように努めており、かつては機能と見なしていたが、実際に使用するプログラマーがほとんどおらず、後になって誤機能として認識された言語の暗い部分を削除してきました。

Luaバージョン4

バージョン3.2までは、一度にアクティブにできるLua「状態」は1つだけでした。状態を変更するためのAPI関数はありましたが、使いにくいものでした。シンプルにするために、APIを設計するときに、関数に明示的な状態パラメーターを含めませんでした。単一のグローバル状態でした。今から考えると、それは間違いでした。Lua 3.2がリリースされるまでに、多くのアプリケーションで複数のLua状態を便利な方法で実行できると、よりシンプルになることが明らかになりました。たとえば、Luaでの動的なページサービングとCGIプログラミングのためのWebブラウザーの拡張であるCGILuaに含めるために、Lua 3.2の特別なバージョンを作成する必要がありました。以前は、ルーカスアーツがLua 3.1に対して同様のことを行いました。

Lua 3.3の計画について議論していたとき、明示的な状態を持つAPIが最優先事項でした。しかし、これにより互換性の問題が発生しました。最終的に、いくつかの非互換性が発生することになるため、APIを書き直すことを決定し、次のバージョンはLua 4.0になりました。APIには明示的な状態が含まれているだけでなく、使いやすく、効率的になっています。Lua 1.1以降、APIを大幅に変更したのは初めてだったので、新しいAPIへの移行は少しトラウマになるのではないかと心配しました。メーリングリストでいくつかの苦情はありましたが、全体として変更はまったくトラウマになりませんでした。ほとんどのLuaプログラマーはAPIに接しておらず、多くのプログラマーは自動ツールを通じてのみAPIを使用し、多くのプログラマーはメリットが移行コストを上回ると考えていました。

2000年11月にLua 4.0をリリースしました。このバージョンでは、新しいAPIに加えて、他にも多くの小さな機能強化が導入されました。その中にはforループがあります。

プログラミング言語に関わる人なら誰でも、人々がこの主題について「宗教戦争」を始めるのがいかに簡単かを知っています。これらの戦争の興味深い特徴は、通常、主題が平凡であればあるほど、議論が白熱化するということです。たとえば、人々は高階関数について議論するよりも、セミコロンについて議論する方がはるかに興奮します。もちろん、その理由の1つは、後者よりも前者について意見を持っている人がはるかに多いということです。しかし、もう1つのより重要な理由は、平凡な詳細が、人々が言語にどれだけ快適に感じるかに大きな影響を与えるということです。優れたグリップがないツールは、どんなに素晴らしく、よく考え抜かれたツールを作成しても無駄です。誰も使用しません。

バージョン1.1以降、forステートメントは、ほとんどのLuaユーザーの要望リストにありました。最も一般的な不満は、whileループの最後にインクリメントを書くのを忘れて無限ループに陥ってしまうことでした。

合意に達するまでそれほど時間はかかりませんでした。しかし、私たちは皆、forループの必要性については同意したものの、特定の構文については合意できませんでした。Pascal風(またはModula風)の構文は、テーブルの要素やファイルの行を反復処理することを考慮していないため、制限が厳しすぎると考えました。さらに、識別子からを予約語にすることは、容認できない非互換性となるでしょう。一方、C言語の伝統的なforループはLuaには適合しませんでした。

バージョン3.1(1998年7月)でクロージャと無名関数が導入されたことにより、反復処理に高階関数を使用することに決定しました。(実際、イテレータの必要性は、Luaに無名関数を導入する主な理由の1つでした。)Lua 3.1では、反復処理のために2つの定義済みの関数が提供されました。

  foreach(table, f)
  foreachi(table, f)
それらはforeach関数はfを、指定されたテーブル内のすべてのキーと値のペアに、特定の順序なしで適用します。foreachi関数は似ていますが、テーブルをリスト(または配列)として扱います。つまり、数値インデックスを持つ要素のみを走査し、昇順で走査することを保証します。これらの2つの特定の走査に対してのみ関数を提供しましたが、新しいイテレータを作成するのは非常に簡単でした。

これらの反復関数を導入してから2年以上経過した後、新しいイテレータを作成するのは簡単でしたが、ほとんど誰もそうしないことに気づきました。最初の理由は、ほとんどのプログラマーが、主に手続き型言語の中で、無名関数と高階関数に慣れていないためです。しかし、2番目であり、私たちの見解では最も重要な理由は、ほとんど誰も他のイテレータを必要としていなかったことです。それは、長年にわたり、私たちが真のユーザーが実際には気にしていなかった直交性を達成しようとしていたことを意味します。この理解に基づき、私たちはすぐにforループを設計しました。2つの形式があり、1つは数値ループ用、もう1つはテーブルの走査用です。

それらはforステートメントは、言語の最初のバージョン以来、最も成功した変更の1つでした。第一に、それはほとんどの一般的なループを本当にカバーしています。本当に汎用的なループのためには、whileループがあります。第二に、その厳格な形式のため、ループを実装するための特定のオペコードを簡単に作成できるため、空の本体を持つ数値forループは、同等のwhile構文よりも2倍以上高速に実行されます。

結論

現在、Luaには確立されたユーザーベースがあります。Luaには活発なディスカッションリストがあり、30か国以上から約500人が参加しています。そのWebサイト(www.lua.org)は、50か国から1日に約500件のアクセスを受けています。その用途は、アドベンチャーゲームからWebサーバー、電話ネットワークテスト、イーサネットスイッチまで多岐にわたります。

いくつかのftpサイトで元のLuaソースコードが提供されており、Windows用DLL、EPOC用SIS、Linux用RPM、RISC OS用バイナリなど、特定のプラットフォーム用のバージョンを配布しているサイトもいくつかあります。さらに、いくつかの雑誌が補足CDでLuaを配布しています(例:Dr. Dobb's、Linux Magazine France、日本のC Magazine)。

言語として、Luaの主な貢献は、機能の代わりにメタメカニズムを提供することにした結果です。製品としてのLuaの成功は、そのシンプルさ、サイズの小ささ、および実装の移植性から来ており、これにより、Luaはパームトップ、ハンドヘルド、特殊なボード、ロボットなどの小型デバイスを含む、多くの異なるプラットフォームで使用できます。キャメロン・レアードとキャスリン・ソレイズは、1998年に「遍在する組み込み処理(あなたの車、配管、キッチン家電のコンピューター)の差し迫った爆発は、Luaに有利に働くしかない」と予測しました[20]。当時、私たちはあまり注意を払っていませんでしたが、彼らは正しかったです。

Luaは、Lua自体と、関連技術としてのLuaの使用に関する、いくつかの論文と論文を通じて、いくつかの学術的な貢献も行っています[4,29,14,17,13,28,15,22,6,27,9,5,7,8]。

成功には代償が伴います。言語の進化を通じて、以前のバージョンとの互換性は、イノベーションをますます阻害する要因になっています。それにもかかわらず、互換性によって進歩を止めることはありません。それは、言語設計の錬金術におけるもう1つの(ただし強力な)要素にすぎません。

最後に、言語を維持することは、それを設計することよりもはるかに多くのことを意味します。言語設計、実装、ドキュメント、ユーザーコミュニティの構築と彼らの意見を聞きながら、同時に元の設計決定を維持するなど、あらゆる側面で細部への完全な注意が不可欠です。

謝辞

Luaは、多くの人々の助けなしには現在の姿にはなっていなかったでしょう。TeCGrafの全員が、さまざまな形で貢献しました。言語を使用したり、議論したり、TeCGrafの外部に広めたりしました。いつも私たちを励まし、言語とその実装に対する完全な自由を与えてくれたTeCGrafの責任者であるマルセロ・ガタスに特に感謝します。Luaは実際、インターネットで一般公開された最初のTeCGraf製品でした。ブームの前でさえも。

ユーザーがいなければ、Luaはまた別の言語にすぎなかったでしょう。ユーザーとその用途は、言語の究極のテストです。彼らから、バグレポート、設計上の欠陥、現実を見る新しい方法を得ました。提案、苦情、そして特に、私たちの時々独裁的なスタイルに耐えてくれたディスカッションリストのメンバーに特に感謝します。

参考文献

[1] K. Beck. Extreme Programming Explained: Embrace Change. Addison-Wesley, 2000.

[2] G. Bell, R. Carey, and C. Marrin. The Virtual Reality Modeling Language Specification–Version 2.0. http://www.vrml.org/VRML2.0/FINAL/, Aug. 1996. (ISO/IEC CD 14772).

[3] T. J. Bergin and R. G. Gibson, editors. History of Programming Languages, volume 2. ACM Press, 1996.

[4] A. Carregal and R. Ierusalimschy. Tche – a visual environment for the Lua language. In VIII Simp�sio Brasileiro de Computa��o Gr�fica, pages 227–232, S�o Carlos, 1995.

[5] W. Celes. Modelagem configur�vel de subdivis�es planares hier�rquicas. PhD thesis, Dep. Inform�tica, PUC-Rio, Rio de Janeiro, Brazil, 1995.

[6] R. Cerqueira, C. Cassino, and R. Ierusalimschy. Dynamic component gluing across different componentware systems. In DOA'99 – International Symposium on Distributed Objects and Applications, pages 362–371, Edinburgh, Esc�cia, 1999. IEEE Computer Society.

[7] M. T. M. de Carvalho. Uma estrat�gia para o desenvolvimento de aplica��es configur�veis em mec�nica computacional. PhD thesis, Dep. Engenharia Civil, PUC-Rio, Rio de Janeiro, Brazil, June 1995.

[8] R. F. de Gusm�o Cerqueira. Um Modelo de Composi��o Din�mica entre Sistemas de Componentes de Software. PhD thesis, Dep. Inform�tica, PUC-Rio, Rio de Janeiro, Brazil, Aug. 2000.

[9] M. J. de Lima, N. Rodriguez, and R. Ierusalimschy. Remote functions as first-class values in a distributed object system. In IV Simp�sio Brasileiro de Linguagens de Programa��o, pages 1–14, Recife, May 2000.

[10] L. H. Figueiredo, R. Ierusalimschy, and W. Celes. The design and implementation of a language for extending applications. In XXI Semish, pages 273–284, Caxambu, 1994.

[11] L. H. Figueiredo, R. Ierusalimschy, and W. Celes. Lua: An extensible embedded language. Dr. Dobb's Journal, 21(12):26–33, Dec. 1996.

[12] L. H. Figueiredo, C. S. Souza, M. Gattass, and L. C. G. Coelho. Gera��o de interfaces para captura de dados sobre desenhos. In Proceedings of SIBGRAPI '92 (Brazilian Symposium on Computer Graphics and Image Processing), pages 169–175, 1992.

[13] P. R. Gomes, B. Feij�, R. Cerqueira, and R. Ierusalimschy. Reactivity and pro-activeness in virtual prototyping. In I. Horvath and A. Taleb-Bendiab, editors, 2nd International Symposium on Tools and Methods for Concurrent Engineering, pages 242–253, Manchester, U.K., Apr. 1998.

[14] T. G. Gorham and R. Ierusalimschy. Um sistema de depura��o reflexivo para uma linguagem de extens�o. In R. Bigonha, editor, I Simp�sio Brasileiro de Linguagens de Programa��o, pages 103–114, Belo Horizonte, Sept. 1996.

[15] A. Hester, R. Borges, and R. Ierusalimschy. Building flexible and extensible Web applications with Lua. Journal of Universal Computer Science, 4(9):748–762, 1998. http://medoc.springer.de:8000/.

[16] R. Ierusalimschy, W. Celes, L. H. Figueiredo, and R. de Souza. Lua: Uma linguagem para customiza��o de aplica��es. In VII Simp�sio Brasileiro de Engenharia de Software – Caderno de Ferramentas, page 55, Rio de Janeiro, Brazil, 1993.

[17] R. Ierusalimschy, R. Cerqueira, and N. Rodriguez. Using reflexivity to interface with CORBA. In IEEE International Conference on Computer Languages (ICCL'98), pages 39–46, Chicago, IL, May 1998. IEEE Computer Society.

[18] R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. Lua–an extensible extension language. Software: Practice and Experience, 26(6):635–652, 1996.

[19] R. Ierusalimschy, L. H. Figueiredo, and W. Celes. Reference manual of the programming language Lua. Monografias em Ci�ncia da Computa��o 3/94, PUC-Rio, Rio de Janeiro, Brazil, 1994.

[20] C. Laird and K. Soraiz. 1998: Breakthrough year for scripting. SunWorld, Aug. 1998. http://sunsite.icm.edu.pl/sunworldonline/swol-08-1998/swol-08-regex.html.

[21] L. Lamport. LaTeX: A Document Preparation System. Addison-Wesley, 1986.

[22] M. C. Martins, N. Rodriguez, and R. Ierusalimschy. Dynamic extension of CORBA servers. In Euro-Par'99 Parallel Processing, pages 1369–1376, Toulouse, France, 1999. Springer-Verlag. (LNCS 1685).

[23] D. Nguyen, T. Gaetz, D. Jerius, and I. Stern. Modeling AXAF obstructions with the generalized aperture program. In Astronomical Data Analysis Software and Systems VI, pages 485–487, Sept. 1996.

[24] Open Software Foundation. OSF/Motif Programmer's Guide. Prentice-Hall, Inc., 1991. (ISBN 0-13-640673-4).

[25] J. Ousterhout. Tcl: an embeddable command language. In Proc. of the Winter 1990 USENIX Conference. USENIX Association, 1990.

[26] E. D. Rather, C. H. Moore, and D. R. Colburn. The evolution of Forth. In ACM SIGPLAN History of Programming Languages Conference, Apr. 1993.

[27] N. Rodriguez and R. Ierusalimschy. Dynamic reconfiguration of CORBA-based applications. In J. Pavelka, G. Tel, and M. Barto\vsek, editors, SOFSEM'99: 26th Conference on Current Trends in Theory and Practice of Informatics, pages 95–111, Milovy, Czech Republic, 1999. Spinger-Verlag. (LNCS 1725).

[28] N. ロドリゲス, R. イェルサリムスキー, および R. セルケイラ. CORBAコンポーネントによる動的な構成. 第4回構成可能分散システム国際会議 (ICCDS'98), pp. 27–34, アナポリス, メリーランド州, 1998年5月. IEEE Computer Society.

[29] N. ロドリゲス, C. ウルラヒ, R. イェルサリムスキー, および R. セルケイラ. 分散システムにおける並列アルゴリズムの実装のためのインタプリタ言語の利用. L. ブーグ, P. フレニョー, A. ミニョット, および Y. ロベール, 編, Euro-Par'96 並列処理 – 第2回国際Euro-Par会議, pp. 597–600, 第1巻, リヨン, フランス, 1996年8月. Springer-Verlag. (LNCS 1123).

[30] L. ウォール および R. L. シュワルツ. Programming Perl. O'Reilly & Associates, Inc., 1991.

[31] R. L. ウェクセルブラット, 編. History of Programming Languages. Academic Press, 1981.