web-dev-qa-db-ja.com

メタプログラミングの用途は何ですか?

もう読んだ:

そして、私はメタプログラミング/コード生成の背後にある目的でいくつかの混乱を告白します。

メタプログラミング/コード生成を使用する具体的な例はありますか?それが代替案よりも優れていた理由の説明が付随するのがさらに良いでしょう。

editThistle はメタプログラミングと見なされますか?

70
Wayne Werner

車を作る男を想像してみてください。コンピュータを使用するのと同じことだとしましょう。
ある時点で、彼は多かれ少なかれ常に同じことをしていることに気付きます。
それで、彼は自動車を作るために工場を建てます、そしてそれははるかに優れています。彼は今プログラミング中です!
それにもかかわらず、もう一度、ある時点で、彼は自分が常に同じことをある程度行っていることに気付きます。
今、彼は自動車を製造する工場を建設する工場を建設することにしました。それはメタプログラミングです。

メタプログラミングは非常に強力ですが、システムの1つの不具合により、すべての利点がモンスターの困難に変わります。だからそれを習得し、それを使用してください...または近づかないでください!

112
Benoît

私はメタプログラミングを「他のプログラムを作成(または変更)するプログラム」と考えています。 (別の答えは「工場を作る工場」、ニースの類推)でした。

人々はこれのあらゆる用途を見つけます:アプリケーションのカスタマイズ、ボイラープレートコードの生成、特別な状況向けのプログラムの最適化、DSLの実装、直交設計問題(「アスペクト」)を処理するコードの挿入...

注目に値するのは、この断片的な処理を実行するために発明されたさまざまなメカニズムの数です。テキストテンプレート、マクロ、プリプロセッサ条件、ジェネリック、C++テンプレート、アスペクト、リフレクションなどです。通常、これらのメカニズムのいくつかは、一部の言語に組み込まれています。他の言語から他の言語へのメカニズム、そしてほとんどの言語にはメタプログラミングのサポートがまったくありません。このように機能が散在しているため、ある言語である種のメタプログラミングを制限付きで実行できても、別の言語では実行できない可能性があります。それは悪化しています:-}

私がここまで行ってきたことは、any言語で動作する汎用のメタプログラミング機構を programの形式で構築できることです。変換 。プログラム変換はパラメーター化されたパターンです。「this構文が見つかった場合は、that構文」。

通常、1つの変換だけでは印象的ではありませんが、数十または数百の変換によってコードに目を見張るような変更を加えることができます。 (高度な)プログラム変換は事実上Turingマシンをシミュレートできるため、散布ショットで見つかったすべてのポイントワイズテクニックを含む、任意のコード変更を実行できます。

言語定義を受け入れるツール。言語固有の変換およびそれらの変換を適用する別の変換は、meta-metaprogrammingツールです:「プログラムを書くプログラム」を書くプログラム。

価値は、そのようなツールを適用して、任意のコードにさまざまな変更を実行できることです。また、特定の種類のメタプログラミングサポートが必要であることを理解するために言語設計委員会を必要とせず、急いでそれを提供して今日の仕事に取り掛かることができます。

興味深い教訓は、そのような機械は、コードのどこに問題があるかに焦点を当てるのに役立つ強力なプログラム分析(シンボルテーブル、制御およびデータフロー分析など)のサポートを必要とするため、メタプログラミング機械はその時点で何かを実行できます(非常にこれの弱い種類の例は、「このように見える場所で変更を加える」と言うアスペクトのポイントカット仕様です)。

OPは、メタプログラミングが適用された具体的な例を求めました。 「メタ」メタプログラミングツール( DMS Software Reengineering Toolkit )を使用して、largeで次のアクティビティを実行しましたコードベースを自動的に:

  • 言語移行
  • テストカバレッジとプロファイラーの実装
  • クローン検出の実装
  • 大規模なアーキテクチャのリエンジニアリング
  • 工場制御のためのコード生成
  • 組み込みネットワークコントローラーのSOA化
  • メインフレームソフトウェアのアーキテクチャ抽出
  • 配列計算からのベクトルSIMD命令の生成
  • 概念に戻るコードのリバースエンジニアリング

java、C#、C++、PHPなど、多くの言語で.

OPはまた、「なぜこれが代替案より優れているのか」と尋ねました。答えは、規模、時間、精度に関係しています。

大規模なアプリケーションの場合、コードベースのサイズが大きいため、そのような分析や変更を手動で行うためのリソースや時間がないことになります。

コード生成または最適化タスクの場合、手動で実行できる場合がありますが、ツールを使用するとはるかに高速かつ正確に実行できます。

本質的に、これらのツールは人間が単純にできないことを実行します。

ツールには創造性がないことは注目に値します。たとえば、タスクの内容を決定するために(例については上記のリストを参照)、効果を達成するための分析/変換を定義する方法を決定するなど、人間に何をさせるかを決定する必要があります。まだmeta-programmersが必要です。ただし、メタプログラマーがこのようなツールに適切な知識を備えている場合、結果として得られるコードは、非常に高速で創造的なエキスパートコーダーによって構築されたように見えます。

20
Ira Baxter

異なるAPI間をブリッジするためのメタプログラミングを最大限に活用しました。

実用的な例はFireBreathsです JSAPIAuto1 これにより、JavaScriptに公開されるC++クラスの記述が容易になります。公開される関数の登録機能を提供することにより、引数の型を検査でき、コンパイル時に生成されたスクリプトのAPI型からネイティブC++型に変換する変換コードから、mapを直接サポートすることさえできます、vectorなど.

簡単な例として、いくつかのスクリプトAPIタイプを使用する公開されたadd(a, b)関数を考えます。

ScriptVariant add(const std::vector<ScriptVariant>& values) {
    // have to check argument count
    if(values.size() != 2)
        throw script_error("wrong number of arguments");

    try {
        // have to convert from scripting-API types
        long a = values[0].convert_cast<long>();
        long b = values[0].convert_cast<long>();
        return a+b; // potentially need to convert back too
    } catch(ScriptVariant::bad_cast& e) {
        // need to handle conversion failure
        throw script_error("conversion failed :(");
    }
}

そこに埋め込まれている実際のロジックは1行だけなので、チェックと変換は煩わしく冗長です。前述の登録機能を使用すると(例:コンストラクター内):

registerMethod("add", make_method(this, &MyClass::add));

これは単に次のように書くことができます:

long add(long a, long b) {
    return a+b;
}

...そしてフレームワークがあなたのために必要なコードを生成します。

1:私は少し実装を行いますが...クリーン...もう一度やり直さなければならない場合

5
Georg Fritzsche

私の最近(過去6か月)のコード生成の具体例:

  1. 他のSQL Plusスクリプトを生成して実行するSQL Plusスクリプトがあります。生成スクリプトは、タイムスタンプフィールドを持ついくつかのテーブルに対してクエリを実行します。スクリプトを設計したとき、選択する時間枠を知ることができませんでした。したがって、メインスクリプトはその作業を行い、サブスクリプトで必要な時間範囲を特定します。次に、コードをファイルに書き込んで(および実際の開始時間と終了時間をプレースホルダーに置き換えて)、添え字を生成します。最後に、添え字を実行します。サブトリックの構造が以前のステップの結果に依存するいくつかの状況で、このトリックを使用しました(多くの場合、これよりも複雑です)。

  2. かつて、XSDからデータベースのテーブル列に要素をマッピングするスプレッドシートを取得しました。マクロとVBAを使用して、スプレッドシートからXSLスニペットと完全なクエリを生成することが可能でした。これらのスニペットとクエリは、それらを実行して結果を処理するシステムにコピーされて貼り付けられます(ほとんどの場合、必要な変更はありません)。見事な解決策ではありませんが、確かに非常に退屈な作業がはるかに退屈なものになり、結果として得られたコードは、1週間か2週間かけてすべてを手作業で作成した場合よりもはるかに一貫性のあるものになりました。

SOメタプログラミングの例のリスト: C++で見たメタプログラミングの最もクールな例は何ですか?

私は自分の具体的な例をあげることができます。私は [〜#〜] abse [〜#〜] を開発しています。これはメタプログラミングアプローチです。 ABSEを使用して、各アイテムが「Atom」であるモデル(実際にはツリー)を作成します。これはAtomは「概念」を表し、その定義に必要なメタデータを含みます。

ABSEでは、概念の実装は実際には「ミニプログラム」です。

次に、ホストモデラー( AtomWeaver 、ABSEと共に開発)がモデルを取得し、そのすべてのAtomからジェネレータープログラムを「織り込み」ます。次に、そのプログラムが実行され、必要なアーティファクト(ソースコード、データなど)が生成されます。

したがって、ABSEワークフローは次のとおりです。

  1. 個別のコンセプト(メタメタプログラムの一部)を作成する
  2. モデルでその概念を再利用する(メタプログラムを効果的に構築する)
  3. ホストモデラーがメタプログラムを作成して実行する
  4. メタプログラムが最終的なプログラムを生成します

一見すると、これは冗長で複雑な作業がたくさんあるように見えますが、概念を理解すれば、実際には非常に簡単です。

メタプログラミングの利点(ABSEに限定されない)?:

  • モデルの変更と完全なシステムの再生成(ソース行ではなくリファクタリング機能を想像してください)。
  • モデルのいくつかの定義を変更すると、個別のプログラム(ソフトウェア製品ファミリー)になる可能性があります。
  • テンプレートを再利用することで、テンプレートのコードを変更し、コードを再生成して、数十、数百の場所でコードを変更できます。
  • 他の多く、本当に

メタプログラミング、コード生成、プログラム変換は、ソフトウェア開発における新しい刺激的な世界です。ただし、メタプログラミングには、メタ思考という新しいスキルが必要です。

メタ思考は、「自分の開発についてどう考えるか」と定義できます。自分に適用される一種のクラス反射。実際には、独自の開発パターンを見つけて分離し、それらを一般的なものにしてから、ABSE、DSL、DSMなどのお気に入りの手法を使用してメタプログラムに変換する必要があります。

3
Rui Curado

メタプログラミングベースのライブラリ/コードは、使用するパラメーターに応じて、実装の詳細コードを生成する明示的で単純なコードを直接記述するのに役立ちます。

Boost は、メタプログラミングで実現できることを示す(C++)ライブラリでいっぱいです。 [〜#〜] dsl [〜#〜]Spirit の実装を可能にする Proto の良い(そしておそらく理解しにくい)例があります。 [〜#〜] ebnf [〜#〜] 文法をコード内で直接使用してコンパイラーを作成できるようになり、他の多くの熱心なライブラリーも使用できます。

2
Klaim

メタプログラミング手法を使用する私の具体的な例を説明しようと思います。

MS Accessのデータ入力フォームからASP.NET Webページのソースコードを生成するプログラムツールを作成しました。私が使用した手法は、フォームコントロールの種類ごとに独自のASP.NETテキストテンプレートを作成することでした。 MS AccessフォームオブジェクトのメタデータからTOP、LEFT、HEIGHT、WIDTH、CONTROLSOURCEなどの値をプラグインしました。たとえば、ASP.NETテキストボックスのテンプレートは次のようになります。

 <asp:TextBox ID="**ID**" runat="server" style="z-index: 1; left: **LL**px; top: **TOP**px; position: absolute"  Text='<%# Bind("[**CTLSOURCE**]") %>' />

テキストボックスコントロールのメタデータ値を取得した後、プログラムがテキストボックスのコードを生成します

<asp:TextBox ID="txtCustomerID" runat="server" style="z-index: 1; left: 50px; top: 240px; position: absolute"  Text='<%# Bind("[CustomerID]") %>' />

私のプログラムは、2〜3秒で1つのMS AccessフォームのWebページのソースコード全体を生成します。数時間または数日かかる可能性のあるタスク。

24-35フォームのMS Accessデータベースを想像してください。すべてのフォームをASP.NET Webページのソースコードとしてコード化するには、数か月ではなく数週間かかる場合があります。この場合、メタプログラミングテクニックを備えた変換ツールを使用します。 、Webページの開発時間を数週間から数か月から数時間に短縮します。

2

有用なアプローチとなる具体的な例。

サードパーティのクラスのセットがあり、そこに一般的な動作を追加したい場合-たとえば、ある種のセキュリティ/アクセス制御、オブジェクトをJSONとしてマッピングするなど.

すべてのサブクラスを作成または生成し、ラッパーメソッドを追加してアクセス制御を追加し、スーパークラスを呼び出すことができます。メタプログラミングを使用すると、実行時にそれを行うことができ、変更はサードパーティの追加/変更されたクラスに自動的に適用されます。

JSONの例では、クラスのイントロスペクションを使用して、オブジェクトをシリアル化するコードを生成し、これをメソッドとしてクラスに追加できます。他の極端な例としては、コードを事前に(コンパイル前に)生成または記述し、クラスが変更されるたびに影響を与えるか、またはマッピングするたびに、個々のオブジェクトのイントロスペクションを使用する完全に一般的なアプローチを使用します。

問題の言語とランタイムに応じて、メタプログラミングアプローチは完全にジェネリック/イントロスペクティブアプローチよりも高速になる可能性がありますが、コードへのデータルックアップの数を減らしたため、その先行コードは遅くなります。

メタプログラミングが言語に直接存在しない場合、それはフレームワーク(つまり、SpringのようなIoCスタイルのコンテナー)を通じて再発明されることが多いようです。

1
JulesLt

Visual Studio(Eclipse、Netbeansなど)を起動します。新しいプロジェクトを作成します。サプライズ-テンプレートからプロジェクトを作成して、メタプログラミングを使用しました。実用的ではないですか?

1
SK-logic

VBAでプロパティを作成するために、メタプログラミングをよく使用します。多数のヘッダーが付いたさまざまなExcelスプレッドシートがあり、各ヘッダーのゲッター/セッタープロパティを定義して、そのヘッダーの下のセルを操作できるようにします。これを手動で行うのは悪夢です。

私たちが選択したメタプログラミングフレームワークは、Notepad ++とその検索/置換正規表現機能でした。プロパティをメタプログラミングした方法を次に示します。

  • ヘッダーのリストをExcelからNotepad ++にコピーする
  • Notepad ++マクロを記録して、データをクリーンアップします(空白と特殊文字を削除します)。この最後に、改行で区切られた文字列のリストがあります。
  • リストを別の.CSVファイルに手動でコピーし、Excelを使用して行番号のリストを生成します。次に、Notepad ++にコピーして戻します。
  • 正規表現を記述して、プロパティ名をプロパティ定義に変換し、すべての空白、キーワードなどを追加します。プロパティ定義の列番号として行番号を使用します。

この最後に、手動のステップ、記録されたマクロ、および正規表現を組み合わせたプロセスがあり、シートのプロパティが必要になるたびに再適用できます。そしてやった!大きな効果に。

それがメタプログラミングの力です。いつ使用するかは経験/直感の問題です。しかし、私はこの質問に答えることをお勧めします:

これを直接コーディングする方が速いのですか、それともプロセスの一部/すべてを自動化してプロセスをスピードアップできるのでしょうか?

これにより、メタプログラミングが役に立たなくなってしまう線が引かれます。速くコーディングできれば、10回繰り返しても、やるだけです!それが何百回もの繰り返しである場合、またはそれが将来何度も再利用することが予想されるものである場合にのみ、それをメタプログラムします。

もう一つのポイントは、ここに学位があるということです。私はかつてJavaプログラムを作成して、新しいIntelliJ検査を検査コーディングプロジェクトに追加するための一連のファイルを作成しました。これはかなりのオーバーヘッドでした:Javaプロジェクトの作成とコンパイルなど。一方、Notepad ++の検索/置換は、手動で入力する上記の小さなステップです。ここでのアドバイスは、手動で作業を開始し、必要に応じて自動化することです。 Javaプログラムは必要ありません。手動で入力する場合はNotepad ++は必要ありません。

0
Colm Bhandal

Common LISPのマクロまたはC++のテンプレートを見て、それらがどのように使用されるかを確認できます。どちらも、使用しているという意味でメタプログラミングです。どちらも多くのコードで頻繁に使用されています。

LISPマクロは、言語を再定義するためによく使用されます。例として、Paul Grahamの最後の章 On LISP は、Common LISPのオブジェクト指向の機能拡張を作成します。もう1つの例は、現在は使用されていない Garnet です。

C++用の古い標準テンプレートライブラリ(主に標準ライブラリに組み込まれています)は、少なくとも統合と効率(構文ではない)の点で、言語に組み込まれているように機能する多数のコンテナーとアルゴリズムを導入する方法でした。

0
David Thornley