web-dev-qa-db-ja.com

スクリプト言語を「埋め込み可能」にするものは何ですか?

私の経験によると、スクリプト言語は Wikipedia および 事前回答 であり、高水準(手動のメモリ管理なし)で解釈される言語の漠然としたカテゴリです。人気のある例は、Python、Ruby、Perl、Tclです。

一部のスクリプト言語は " embedded "にすることができます。例えば:

  • Luaはビデオゲームアプリケーションに頻繁に組み込まれています。
  • TCLはFossilバージョン管理システムに組み込まれています

LuaはPythonよりも簡単に埋め込むことができる または TypeScriptは埋め込むのが難しい と言われることもあります。同様に、 Wren は「アプリケーションへの埋め込みを目的としています」です。

言語を埋め込み可能にする要因は何ですか?基本的な通訳のサイズと速度だけですか、それとも他の要因が関係しますか?

40
Seanny123

言語を埋め込む(「スクリプト」として特徴付けることは避けます)とは、次のことが行われたことを意味します。

  • インタープリターとランタイムは同じプロセスで実行されていますホストアプリケーションとして
  • 十分な標準タイプと標準ライブラリがそのランタイム内からも利用できます
  • ほとんどの場合、アプリケーションには、ホストアプリケーションで使用できる独自のライブラリがあります。

最初の箇条書きは、文字通り埋め込みの定義です。言語をアプリケーションに埋め込む主な理由は、アプリケーションの機能を拡張する簡単な手段を提供することです。理由は次のとおりです。

  • 複雑な手順を可能な限り高速に実行するマクロを作成する(Photoshop、Gimpなど)
  • 技術の少ない人によるゲーム要素のプログラミング(多くのゲームには、MODやキャラクターなどを作成するためのある程度の埋め込み言語があります)

したがって、大きな問題は、埋め込みを簡素化する要因は何かです。

  • インタプリタおよび/またはランタイム環境の複雑さ(シンプルな方が簡単)
  • 標準ライブラリのサイズ(小さいほど簡単です)
  • 間接参照のレイヤー(少ないほど良い、TypeScriptはCに再コンパイルするために使用されたC++のようにJavaScriptに再コンパイルされ、ネイティブのTypeScript環境はありません)
  • 基盤となるアーキテクチャの互換性(いくつかの言語はJavaランタイムまたは.Netランタイムに実装されており、基盤となる環境の類似性により、組み込みが容易になります)

結論として、幅広い言語を別のアプリケーションに埋め込むことが可能です。場合によっては、大変な作業がすでに行われているため、アプリに言語を含めるだけで済みます。たとえば、IronPythonは.Net上に構築され、JythonはJavaに基づいて構築されているため、これらのプラットフォームで構築されたアプリケーションにPythonを簡単に埋め込むことができます。

実装がどれほど堅牢で完全であるかに関しては、複雑な結果が得られます。他のプロジェクトより成熟しているプロジェクトもあります。一部の言語は実装が簡単です(LISPが最初の組み込み言語の1つであった理由があります)。

40
Berin Loritsch

主な要因は、通常、言語ライブラリにアクセスするためにホストアプリケーションによって使用されるAPIです。 Luaのような言語は、ホストアプリケーションから簡単に「接続」できるように設計されています。言語はライブラリ形式で利用できる場合があり、APIは他の言語から簡単に呼び出すことができます(通常はプレーンなC API)。 APIは通常、スクリプトを実行し、特定の状況(未定義の変数など)に応答するようにコールバックを設定し、ホストアプリケーションのリソース/ guiにアクセスするための関数を提供します。かなり簡単にできるAPIは、そうでないAPIよりも「埋め込み可能」です。

10
GrandmasterB

理論的には、任意の言語を埋め込むことができます。ソリューションに制約がない場合は、実際にそうです。チューリングの完全性の当然の結果です。つまり、いつでもエミュレータを構築できます。

私があなたが尋ねていると思うのは、「この目的のために言語を実用的にするものは何ですか」です。言語をこれに適したものにする主なものの1つは、実装ではなく動作の観点から定義されたものだと思います。問題の言語に、メモリ内でのint値の表現方法に関する非常に具体的なルールがある場合、たとえば、整数に関する考え方がまったく同じではない別のアプリケーションの上で実行すると、問題が生じます。

これの良い例は、Pythonです。これは、それがどのように動作するかという点で定義され、それがどのように実装されるかについてほとんど言いません。これは、完全に機能するPythonインタプリタはJava(またはC#など)型のファサードとして機能します。つまり、Pythonスクリプトを実行できるだけではありません、それを使用して、Javaで記述されたアプリケーションの一部と対話できます。

別の要因は、言語のセマンティクスの単純さです。言語が複雑になるほど、明白な理由でその言語のインタープリターを構築することが難しくなる傾向があります。

10
JimmyJames

いくつかの要因があります:

  • 言語がAPIの埋め込みをサポートしているかどうか。 Pythonのような一部のスクリプト言語と、Luaはこれらの言語をホストアプリケーションに埋め込むために特別に設計されたAPIを公式にサポートしています。これには、言語が外部関数インターフェイス、外部オブジェクトハンドル、外部クラスと対話する方法の指定が含まれます。など、外部言語がその言語のオブジェクトを呼び出して操作するためのAPIを指定します。埋め込み用に設計された言語を使用すると、これらの外部オブジェクトを通常のクラスやオブジェクトのように表示および動作させることができます。複雑なラッパークラスはありません= Pythonこれは非常に得意です。

  • 埋め込み用に設計された言語実装は、多くの場合、メインアプリケーションとスレッドを共有するように設計されています。これは、UI要素は通常、UIスレッドからのみ更新できるため、埋め込み言語のインタープリターは、メインスレッドを完全に引き継がずに、実行、メインスレッドへの変換、UI更新の呼び出し、および実行の再開ができる必要があるためです。埋め込み用に設計されていない言語の実装では、インタープリターが個別のスレッドまたはプロセスで実行され、RPC /メッセージキューメカニズムを介してのみアプリケーションのUIスレッドと通信する必要がある場合があり、これにより大幅なパフォーマンスコストが発生します。

  • メモリの安全性。メモリセーフ言語と直接メモリアクセスのない言語は、スクリプト言語で記述されたコードが直接メモリアクセスのためにメインアプリケーションをクラッシュさせることがないため、埋め込みが簡単です。

  • これらの言語のランタイムサポートの大きさ。大きな標準ライブラリを持つ言語は、アプリケーションのサイズが肥大化することを意味するため、埋め込みに不利になる傾向があります。一方、特定のスクリプト言語が選択された理由が巨大な標準ライブラリである多くのアプリケーションがあるため、スクリプト作成者は、メインアプリケーション自体が直接提供したくない機能に実際にアクセスできます。

  • TypeScriptのような追加の課題は、JavaScriptインタープリターを埋め込むことによってのみ埋め込むことができます。そのため、実際にはTypeScriptのみに関心がある場合でも、JavaScriptインタープリターを埋め込むという追加の課題があります。

6
Lie Ryan

埋め込み可能に設計された言語は、ホストアプリケーションへのアクセスを容易にする機能を提供しようとします。これには、実際の言語の構文とセマンティクス、および埋め込もうとする言語のランタイム実装の2つの層があります。

例えば、両方のPythonとTclは埋め込み可能とラベル付けされています。私の経験から、PythonはTclよりも埋め込みがはるかに困難です(両方で、複数のコンテキスト)。

どうしてこんなことに?

Pythonは意見が分かれており、世界はPOSIX設定のように見えると想定されています。ファイルシステムAPI、コンソールAPI、ネットワークAPIはすべて抽象化されているわけではなく、ほとんどがPOSIX C-APIの直接ラッパーです。 Tclはハードウェアにそれほど近いものではなく、ほとんどのAPIを抽象化しようとし、スクリプトレイヤーに多くの低レベルAPIを提供しません。したがって、Pythonを埋め込む場合は、POSIXのようなファイル抽象化を提供する必要があります。 Tclの場合、ファイルを気にしないのであれば、何もする必要はありません。作業が少なく、埋め込みが簡単です。

(C)Pythonは基本的に、グローバルロック付きのシングルスレッドです。 Tclにはグローバルロックがありません。したがって、ホストアプリケーションがマルチスレッドであり、Python=を埋め込む場合、重要なものについては、アプリケーションにグローバルロックを追加しただけです。したがって、Pythonプログラムははるかに苦痛です。

デフォルトでは、Pythonモジュールシステムはファイルシステムにマップされます。モジュール名とファイルシステム名はリンクされています。そのため、言語は提供するファイルシステムによって制限され、大文字と小文字を区別しないファイルシステムに移植すると突然壊れます。 Tclはモジュールシステムをファイルシステムレイアウトにリンクしなかったため、ファイルシステムは言語のセマンティクスを変更しません。

Pythonは、世界がブロッキングおよび同期(POSIXのような)であることを前提としており、非同期APIを徐々に採用しています。 Tclは、ノンブロッキングAPIとコールバックをより困難にしようとします。ブロッキングAPIを非同期でシミュレートする方が他の方法よりもはるかに簡単なので、通常、実行する作業が少なくなります。

Tclはかなり最小限です。不要なものはすべて簡単に取り除くことができます。ファイルシステムAPIを取り除くように。またはプロセス制御。または正規表現。 Pythonは、組み込みの名前空間に大量のものがあり、バイトコードへの書き込みアクセスのため、信頼できないコードからロックダウンして保護することはほぼ不可能です。純粋なバグとは見なされませんPythonコードはプロセスをクラッシュさせる可能性があります(たとえば、Pythonバイトコードは、生のポインタを使用してそれに書き込む場合があります)。したがって、信頼できないユーザーを実行しようとすると、埋め込みが難しくなります。コード。

Python標準ライブラリは、多くの場合、それが世界を管理していると想定しています。 Tclsはしません。たとえば、Pythonは、メモリ不足の問題が発生したときに爆発してプロセスを強制終了することがよくあります。一部のPython API呼び出しは、重大なエラーをstderrにダンプすることもあります(埋め込み状況(Windowsサービスコンテキストやアプリケーションの強制終了など)には存在しませんが、Tclは通常、クラッシュしたり終了したりせずにアプリケーションに制御を戻そうと非常に努力します。そのため、優れたゲストであることが重要です。

つまり、言語の埋め込みを容易にするものは、優れたゲストのようです。

  • ホスティング環境についてはあまり気にしないでください。ファイルシステムがありません。 stdioがありません。環境変数がありません。世界についてのあなたの仮定をチェックして最小化してください。
  • 自分の後を片付けなさい。自分自身を複数回再初期化できるようにする。
  • ホストのスレッドを邪魔しないでください。
  • 利用可能な機能セットを問題のあるドメインに合わせてカスタマイズできるようにします。
  • 信頼できない入力を実行している場合でも、安全を確保してください。
2
schlenk