メタプログラミングとは、コンピュータプログラムが他のプログラムを自身のデータとして扱う能力を持つコンピュータプログラミング手法です。これは、プログラムが実行中に他のプログラムを読み取り、生成、分析、変換し、さらには自身を変更するように設計できることを意味します。[1] [2]場合によっては、これによりプログラマーは解決策を表現するためのコード行数を最小限に抑えることができ、開発時間を短縮できます。[3]また、プログラムはより柔軟になり、再コンパイルすることなく新しい状況を効率的に処理できるようになります。
メタプログラミングは、計算を実行時ではなくコンパイル時に移し、コンパイル時の計算を用いてコードを生成し、自己書き換えコードを可能にするために用いられる。プログラミング言語が自身のメタ言語となる能力は、リフレクション・プログラミングを可能にし、これはリフレクションと呼ばれる。[4]リフレクションは、メタプログラミングを促進する上で重要な言語機能である。
1970年代から1980年代にかけて、LISPなどのリスト処理言語を用いたメタプログラミングが流行しました。LISPマシンのハードウェアは1980年代に注目を集め、コードを処理できるアプリケーションを実現しました。これらは人工知能アプリケーション でよく利用されました。
メタプログラミングにより、開発者はジェネリックプログラミング パラダイムに則ったプログラムやコードを作成できます。プログラミング言語自体を第一級データ型(Lisp、Prolog、SNOBOL、Rebolなど)として持つことも非常に有用です。これは同図像性と呼ばれます。ジェネリックプログラミングは、データ型をパラメータとして指定できるため、データ型の指定を気にすることなくコードを記述できるようにすることで、言語内でメタプログラミング機能を呼び出します。
メタプログラミングは通常、3つの方法のいずれかで機能します。[5]
Lispは、歴史的な先行性とメタプログラミングのシンプルさと強力さの両方から、メタプログラミング機能を備えた典型的な言語と言えるでしょう。Lispのメタプログラミングでは、アンクォート演算子(通常はカンマ)によって、実行時ではなくプログラム定義時に評価されるコードが導入されます。したがって、メタプログラミング言語はホストプログラミング言語と同一であり、既存のLispルーチンを必要に応じてメタプログラミングに直接再利用できます。このアプローチは、プログラムにインタープリタを組み込み、プログラムのデータを直接操作することで、他の言語にも実装されています。RemObjectsのPascal Script for Object Pascalなど、一般的な高級言語にもこの種の実装が存在します。
メタプログラムの簡単な例として、生成プログラミングの例である次のPOSIX シェル スクリプトがあります。
#!/bin/sh
# メタプログラム
echo '#!/bin/sh' > program
for i in $( seq 992 ) do echo "echo $i " >> program
done
chmod +x program
このスクリプト(またはプログラム)は、1から992までの数字を出力する993行の新しいプログラムを生成します。これは、コードを使ってより多くのコードを記述する方法の一例に過ぎず、数字のリストを出力する最も効率的な方法ではありません。とはいえ、プログラマーはこのメタプログラムを1分以内に作成して実行することができ、その時間内に1000行以上のコードを生成することになります。
クワインは、出力として独自のソースコードを生成する特殊なメタプログラムです。クワインは一般的に、娯楽目的または理論的な関心のみを目的としています。
すべてのメタプログラミングが生成的プログラミングを伴うわけではありません。プログラムが実行時に変更可能である場合、または増分コンパイルが利用可能な場合(C#、Forth、Frink、Groovy、JavaScript、Lisp、Elixir、Lua、Nim、Perl、PHP、Python、Rebol、Ruby、Rust、R、SAS、Smalltalk、Tclなど)、ソースコードを生成せずにメタプログラミングを実行するための技術を使用できます。
生成的アプローチの一つのスタイルは、ドメイン固有言語(DSL)を用いることです。DSLの一般的な使用例としては、生成的メタプログラミングが挙げられます。lexとyaccは、字句解析器と構文解析器を生成するツールであり、正規表現と文脈自由文法を用いてユーザーが言語を記述できるようにし、言語を効率的に解析するために必要な複雑なアルゴリズムを埋め込むことができます。
メタプログラミングの 1 つの用途は、動的なプログラム分析を行うためにプログラムをインストルメント化することです。
メタプログラミング機能を完全に使いこなすには、急激な学習曲線があると主張する人もいます。[8]メタプログラミングは実行時に高い柔軟性と構成可能性を提供するため、メタプログラミングを誤用したり不適切に使用したりすると、平均的な開発者にとってデバッグが非常に困難な、不当で予期しないエラーが発生する可能性があります。注意して使用しないと、システムにリスクをもたらし、システムを脆弱にする可能性があります。メタプログラミングの誤った使用によって発生する可能性のある一般的な問題には、不足している構成パラメータをコンパイラが識別できないこと、無効または不正確なデータによって未知の例外や異なる結果が発生することがあります。[9]このため、高度なスキルを持つ開発者だけが言語またはプラットフォームでメタプログラミングを実行する機能の開発に取り組むべきであり、平均的な開発者は慣例の一部としてこれらの機能の使用方法を学習する必要があると考える人もいます [8]。
IBM /360とその派生機種には強力なマクロアセンブラ機能が搭載されており、アセンブリ言語プログラム全体([要出典])やプログラムの一部(例えば、異なるオペレーティングシステム用)を生成するためによく使用されていました。CICSトランザクション処理システムに付属するマクロには、前処理として COBOL文を生成するアセンブラマクロが含まれていました。
MASMなどの他のアセンブラもマクロをサポートしています。
メタクラスは次のプログラミング言語によって提供されます。
依存型の使用により、生成されたコードが無効にならないことを証明できます。[15]しかし、このアプローチは最先端のものであり、研究用プログラミング言語以外ではほとんど見られません。
注目すべきメタプログラミング システムのリストは、プログラム変換システムのリストで管理されています。