Dylanは、関数型プログラミングとオブジェクト指向プログラミング(OOP)をサポートするマルチパラダイムプログラミング言語であり、動的かつリフレクティブな性質を持ちながら、動的および静的な動作をきめ細かく制御するなど、効率的なマシンコードの生成をサポートするように設計されたプログラミングモデルを提供します。1990年代初頭にApple Computerが主導するグループによって開発されました。
DylanはSchemeとCommon Lispをベースとし、 Common Lispオブジェクトシステム(CLOS)から派生した統合オブジェクトシステムを追加しています。Dylanでは、すべての値(数値、文字、関数、クラスを含む)が第一級オブジェクトです。Dylanは多重継承、ポリモーフィズム、多重ディスパッチ、キーワード引数、オブジェクトイントロスペクション、パターンベースの構文拡張マクロ、その他多くの高度な機能をサポートしています。プログラムは動的プログラミングと静的プログラミングの中間に位置するプログラムを許容し、進化的な開発(迅速なプロトタイピングとその後の段階的な改良および最適化を可能にする)をサポートするため、動的な動作をきめ細かく制御できます。
Dylanの主な設計目標は、商用ソフトウェアの開発に適した動的な言語となることです。Dylanは、 Lispシステムの完全な柔軟性に「自然な」制限を設けることで、潜在的なパフォーマンスの問題に対処しようとしています。これにより、コンパイラはライブラリなどのコンパイル可能な単位を明確に理解できるようになります。
Dylanは、そのセマンティクスの多くをSchemeや他のLispから派生させており、一部のDylan実装は当初、既存のLispシステム内で構築されました。しかし、DylanはLispのような接頭辞構文ではなく、ALGOLのような構文を採用しています。
Dylanは1990年代初頭にApple Computerが主導するグループによって開発されました。開発段階では、Apple Newtonコンピュータでの使用を想定していましたが、Dylanの実装が十分な成熟度に達するには至らず、Newtonは代わりにC言語とWalter Smithが開発したNewtonScriptを組み合わせて使用しました。Appleは1995年にDylanの開発を終了しましたが、高度な統合開発環境(IDE)を搭載した「テクノロジーリリース」バージョン(Apple Dylan TR1)を公開しました。
他に2つのグループが言語設計に貢献し、実装を開発しました。HarlequinはMicrosoft Windows向けの商用IDEをリリースし、カーネギーメロン大学はUnixシステム向けのオープンソースコンパイラであるGwydion Dylanをリリースしました。これらの実装はどちらも現在オープンソースとなっています。Harlequinの実装は現在Open Dylanという名称で、Dylan Hackersと呼ばれるボランティアグループによって維持管理されています。
ディラン言語は「ラルフ」というコードネームで呼ばれていた。ジェームズ・ホアキンは「ダイナミック・ランゲージ」の略として「ディラン」という名前を選んだ。
Dylanの構文機能の多くは、Lispの系譜に由来しています。当初、DylanはLispに似た接頭辞構文を使用しており、これはs式に基づいています。言語設計が完了する頃には、より幅広いプログラマーにとって馴染みやすいものになるという期待から、構文はALGOLに似た構文に変更されました。この構文はMichael Kahlによって設計されました。詳細はDylanリファレンスマニュアルに記載されています。[ 2 ]
Dylanは大文字と小文字を区別しません。Dylanの語彙構文では、複数の単語からなる識別子の各部分をハイフン(マイナス)で連結する命名規則(「 lispケース」または「ケバブケース」と呼ばれることもあります)を使用できます。この規則はLisp言語でよく見られます。
Dylanでは、英数字とハイフンマイナス記号に加えて、さまざまな非英数字文字を識別子の一部として使用できます。識別子は、これらの非英数字文字だけで構成することはできません。[ 2 ]曖昧さがある場合は、空白が使用されます。
複数のスロットを持つシンプルなクラス:
define class <point> ( <object> ) slot point-x :: <integer> , required-init-keyword: x: ; slot point-y :: <integer> , required-init-keyword: y: ; end class <point> ;慣例として、クラス名は山括弧として使用される小なり記号と大なり記号で命名されます。たとえば、コード例で命名されたクラスです。<point>
どちらの場合も、とは省略可能です。これはすべての節に当てはまります。たとえば、文を終了させるために、または と記述することもできます。end class <point>class<point>endend ifendif
インスタンスを作成するには:<point>
make ( <point> , x: 100 , y: 200 )同じクラスを、可能な限り最小限の方法で書き直したもの:
define class <point> ( <object> ) slot point-x ; slot point-y ; end ;スロットは両方とも 型になっています。スロットは手動で初期化する必要があります。<object>
let p = make ( <point> ); point-x ( p ) := 100 ; // または p.point-x := 100; point-y ( p ) := 200 ; // または p.point-y := 200;慣例として、定数名は「$」で始まる。
定数$pi :: <double-float> = 3.1415927 d0を定義します。階乗関数:
define function factorial ( n :: <integer> ) => ( n! :: <integer> ) case n < 0 => error ( "負の整数の階乗はできません: %d \n " , n ); n = 0 => 1 ; otherwise => n * factorial ( n - 1 ); end end ;ここで、n!およびは単なる通常の識別子です。<integer>
明示的な戻り値文はありません。メソッドまたは関数の結果は、最後に評価された式になります。戻り値の位置にある式の後にセミコロンを付けないのは一般的なスタイルです。
多くのオブジェクト指向言語では、クラスがカプセル化とモジュール化の主要な手段です。各クラスは名前空間を定義し、どの定義が外部から見えるかを制御します。さらに、多くの言語のクラスは、全体として使用する必要がある不可分な単位を定義します。たとえば、String連結関数を使用するには、すべてのクラスをインポートしてコンパイルする必要がありますString。
Dylanを含む一部の言語は、より一般的な方法でカプセル化を行うための、独立した明示的な名前空間またはモジュールシステムも備えている。
Dylanでは、コンパイル単位とインポート単位の概念は分離されており、クラスはどちらにも直接関係しません。ライブラリは、一緒にコンパイルおよび処理されるべき項目を定義し、モジュールは名前空間を定義します。プログラマの希望に応じて、クラスをモジュール内にまとめて配置することも、モジュールをまたいで配置することもできます。多くの場合、クラスの完全な定義は単一のモジュールには存在せず、複数のモジュールに分散しており、それらを任意にまとめて使用できます。異なるプログラムは、同じクラスに対して、必要な部分のみを含む異なる定義を持つことができます。
例えば、正規表現をサポートするアドオンライブラリを考えてみましょうString。一部の言語では、文字列に機能を含めるには、その機能をString名前空間に追加する必要があります。これが起こるとすぐにStringクラスが大きくなり、正規表現を使用する必要のない関数でもライブラリサイズの増加という形で「代償」を払うことになります。このため、このようなアドオンは通常、独自の名前空間とオブジェクトに配置されます。このアプローチの欠点は、新しい関数がもはやの一部 ではなくなり、代わりに、個別に呼び出す必要がある独自の関数セットに分離されることです。オブジェクト指向の観点から自然な構成であるのString代わりに、のようなものが使用され、事実上順序が逆転します。myString.parseWith(myPattern)myPattern.parseString(myString)
Dylanでは、同じコードに対して複数のインターフェースを定義できます。例えば、文字列連結メソッドは、Stringインターフェースと、さまざまなクラスの連結関数をまとめた「concat」インターフェースの両方に配置できます。これは、関数が多様なオブジェクト型に適用される傾向のある数学ライブラリでよく用いられます。
インターフェース構造のより実用的な用途は、モジュールのパブリックバージョンとプライベートバージョンを作成することです。これは他の言語ではアドオン機能として含まれており、必ず問題を引き起こし、構文を複雑にします。Dylan では、すべての関数呼び出しを「Private」または「Development」インターフェースに簡単に配置でき、パブリックにアクセス可能な関数を にまとめることができます。JavaPublicや C++ では、オブジェクトの可視性はコードで定義されているため、同様の変更をサポートするには、プログラマーは定義を完全に書き直す必要があり、2 つのバージョンを同時に持つことはできません。
Dylan のクラスは、slotsほとんどのオブジェクト指向言語と同様の方法でオブジェクト (データ メンバー、フィールド、インスタンス変数など) を記述します。スロットへのアクセスはすべて、Smalltalkと同様にメソッドを介して行われます。デフォルトのゲッターおよびセッター メソッドは、スロット名に基づいて自動的に生成されます。他のほとんどのオブジェクト指向言語とは異なり、クラスに適用可能な他のメソッドはクラスの外で定義されることが多く、そのため Dylan のクラス定義には通常、ストレージの定義のみが含まれます。例:
define class <window> ( <view> ) slot title :: <string> = "untitled" , init-keyword: title: ; slot position :: <point> , required-init-keyword: position: ; end class ;この例では、クラス" が定義されています。<クラス名>構文は慣例のみで、クラス名を目立たせるためです。山括弧は単にクラス名の一部です。対照的に、一部の言語では、クラス名の最初の文字を大文字にするか、名前の前にCまたはTを付ける慣例があります(例)。は単一のクラス から継承し、ウィンドウのタイトルの文字列とウィンドウの角のXY座標を保持する2つのスロットを持っています。この例では、タイトルにはデフォルト値が設定されていますが、位置には設定されていません。オプションのinitキーワード構文を使用すると、プログラマはクラスのオブジェクトをインスタンス化するときにスロットの初期値を指定できます。<window><window><view>titleposition
C++ や Java などの言語では、クラスはインターフェースも定義します。この場合、上記の定義には明示的な指示がないため、どちらの言語でもスロットとメソッドへのアクセスは とみなされprotected、サブクラスのみが使用できます。無関係なコードがウィンドウ インスタンスを使用できるようにするには、 を宣言する必要がありますpublic。
Dylanでは、こうした可視性ルールはコードの一部ではなく、モジュール/インターフェースシステムの一部とみなされます。これにより、かなりの柔軟性が生まれます。例えば、開発初期段階で使用するインターフェースはすべてを公開する一方、テストやデプロイ段階で使用するインターフェースでは公開範囲を制限するといったことが可能です。C++やJavaでは、こうした変更にはソースコードの変更が必要となるため、誰も実行しませんが、Dylanではこれは全く別の概念です。
この例では使用していませんが、Dylan は多重継承もサポートしています。
Dylanでは、メソッドは特定のクラスに本質的に結び付けられているわけではなく、クラスの外に存在するものと考えることができます。CLOSと同様に、Dylanは多重ディスパッチ(マルチメソッド)に基づいており、呼び出される特定のメソッドは、すべての引数の型に基づいて選択されます。メソッドはコンパイル時に既知である必要はなく、必要な関数が利用可能かどうかは、ユーザーの設定によって決まるという前提に基づいています。
Javaでは、同じメソッドは特定のクラスに分離されています。その機能を使用するには、プログラマーはそのクラスをインポートし、明示的に参照してメソッドを呼び出す必要があります。コンパイル時にそのクラスが利用できない場合、または認識できない場合は、アプリケーションはコンパイルされません。
Dylanでは、コードは関数内でストレージから分離されています。多くのクラスには、独自の関数を呼び出すメソッドがあり、他のほとんどのオブジェクト指向言語と同様の外観と操作感を持っています。ただし、コードは汎用関数内にも配置できます。汎用関数は特定のクラスに紐づかず、誰でもネイティブに呼び出すことができます。特定の汎用関数をクラスのメソッドにリンクするには、次のようにします。
define method turn-blue ( w :: <window> ) w . color := $blue ; end method ;この定義は他の言語のものと似ており、おそらくクラス内にカプセル化されるでしょう。:= セッター呼び出しに注目してください。これはの構文糖衣です。<window> color-setter($blue, w)
汎用メソッドの有用性は、より「汎用的」な例を考えると明らかになります。たとえば、ほとんどの言語で共通する関数の は、オブジェクトの人間が読みやすいto-string形式を返す関数です。たとえば、ウィンドウはタイトルと位置を括弧で囲んで返し、文字列は文字列自身を返します。Dylan では、これらのメソッドをすべて「」という単一のモジュールにまとめることができ、それによってこのコードをクラス自体の定義から削除できます。特定のオブジェクトが をサポートしていない場合は、モジュールに簡単に追加できます。to-stringto-stringto-string
to-stringこの概念全体は、読者によっては奇妙に思えるかもしれません。ウィンドウを処理するコードはに定義されていないのでしょうか? Dylan が の呼び出しをどのように処理するかを考慮するまでは、これは意味をなさないかもしれません。ほとんどの言語では、プログラムがコンパイルされるときに、が検索され、メソッドへのポインタ (多かれ少なかれ) に置き換えられます。 Dylan では、これはプログラムが最初に実行されるときに発生します。ランタイムはメソッド名とパラメータの詳細のテーブルを作成し、このテーブルを介してメソッドを動的に検索します。つまり、特定のメソッドの関数は、コンパイル時ユニットだけでなく、どこにでも配置できます。最終的に、プログラマはコードを配置する場所に関してかなりの柔軟性を持ち、適切な場合はクラスラインに沿って、そうでない場合は機能ラインに沿ってコードをまとめることができます。<window>to-stringto-string<window>
ここで意味するのは、プログラマーが別のファイルで関数を定義することで、既存のクラスに機能を追加できるということです。たとえば、すべての文字列にスペルチェック機能を追加したい場合、C++ や Java では文字列クラスのソースコードにアクセスする必要がありますが、このような基本的なクラスはソースコード形式で提供されることはほとんどありません。Dylan (およびその他の「拡張可能な言語」) では、スペルチェックメソッドをモジュールに追加し、構文を介して適用できるすべてのクラスを定義できます。この場合、実際の機能は、文字列を受け取ってエラーを返す単一の汎用関数で定義できます。モジュールがプログラムにコンパイルされると、すべての文字列 (およびその他のオブジェクト) に機能が追加されます。<string>spell-checkdefine methodspell-check
Apple Dylanは、 Apple Computerが開発したDylanの実装版である。元々はApple Newton向けに開発された。