Oxygene(旧称:Chrome)は、RemObjects SoftwareがMicrosoftの共通言語インフラストラクチャ(CLI)、Javaプラットフォーム、およびCocoa向けに開発したプログラミング言語です。OxygeneはDelphi Object Pascal言語をベースにしており、 C#、Eiffel、Java、F#などの影響を受けています。
現在では非推奨となっているDelphi.NETと比較すると、Oxygeneは完全な後方互換性を重視しておらず、言語の「再発明」を目指し、マネージド開発プラットフォーム上で優れた役割を果たし、 .NETおよびJava仮想マシンランタイムが提供するすべての機能とテクノロジーを活用するように設計されています。
Oxygeneは商用製品であり、Windows上ではMicrosoftのVisual Studio統合開発環境(IDE)に完全に統合され、 macOS上ではFireと呼ばれる独自のIDEを提供しています。Oxygeneは、基盤となるElementsコンパイラツールチェーンでサポートされている6つの言語のうちの1つであり、 C#、Swift、Java、Go、Mercury ( Visual Basic(.NET)ベース)と並んでサポートされています。
2008年から2012年にかけて、RemObjects SoftwareはコンパイラとIDEテクノロジーをEmbarcaderoにライセンス供与し、Embarcadero Prism製品のバックエンドコンパイラとして使用されました。[ 2 ] 2011年秋から、Oxygeneは2つの異なるエディションで利用可能になり、第2エディションではJavaおよびAndroidランタイムのサポートが追加されました。XE4のリリース以降、Embarcadero PrismはRAD Studio SKUの一部ではなくなりました。Prismの顧客がOxygeneに移行するための多数のサポートおよびアップグレードパスが存在します。[ 3 ] 2016年現在、Oxygeneのエディションは1つだけで、WindowsまたはmacOSでの開発が可能で、Windows、Linux、WebAssembly .NET、iOS、Android、Java、macOS用の実行可能ファイルを作成できます。
Oxygene言語は、一般的にはObject Pascal、特にDelphiを起源としていますが、.NETプログラミングのガイドラインを反映し、CLRに完全に準拠したアセンブリを作成するように設計されています。そのため、Object PascalやDelphiでおなじみのいくつかのマイナーな言語機能は削除または改訂され、ジェネリクスやシーケンス、クエリなど、多くの新しい、より現代的な機能が言語に追加されています。
Oxygeneはオブジェクト指向プログラミング言語です。そのため、データを保持しコードを実行できるクラスを使用してプログラムを設計します。クラスはオブジェクトの「プロトタイプ」であり、リンゴという概念が実際に店で買えるリンゴのプロトタイプであるのと同様です。リンゴには色があり、皮をむくことができることは周知の事実です。これらはリンゴクラスのデータと実行可能な「コード」に相当します。
Oxygeneは、並列プログラミングの一部の機能について言語レベルでのサポートを提供します。並列プログラミングの目的は、コンピュータのすべてのコアまたはプロセッサを使用してパフォーマンスを向上させることです。この目的を達成するには、タスクを複数のスレッドに分散する必要があります。.NET FrameworkのThreadPoolクラスは、複数のスレッドを効率的に扱う方法を提供していました。.NET 4.0では、並列プログラミングの機能をさらに充実させるために、タスク並列ライブラリ(TPL)が導入されました。
Oxygeneでは、以下のclass operator構文を使用して演算子をオーバーロードできます。
クラス演算子implicit ( i : Integer ) : MyClass ;演算子オーバーロードの場合、各演算子には名前があり、演算子オーバーロード構文でその名前を使用する必要があることに注意してください。たとえば、「+」は Oxygene では有効なメソッド名ではありません。[ 4 ]
OxygeneはDelphiのように「ユニット」を使用せず、.NET名前空間を使用して型を整理およびグループ化します。名前空間は複数のファイル(およびアセンブリ)にまたがることができますが、1つのファイルには1つの名前空間の型しか含めることができません。この名前空間はファイルの先頭で定義されます。
名前空間 ConsoleApplication1;
Oxygeneファイルは、Delphiでおなじみの構造であるインターフェースセクションと実装セクションに分かれています。インターフェースセクションは名前空間の宣言に続きます。このセクションにはuses、Oxygeneで他の名前空間から型をインポートする句が含まれています。
System.Linqを使用します。インポートする名前空間は、プロジェクト自体、または参照されるアセンブリ内に存在する必要があります。C#とは異なり、Oxygeneでは名前空間にエイリアス名を定義することはできず、単一の型名にのみ定義できます(下記参照)。
そのuses条項に続いて、ファイルにはDelphiでおなじみの型宣言が含まれます。
インタフェースtype ConsoleApp = class public class method Main ; end ;C#と同様に、Mainメソッドはすべてのプログラムのエントリポイントです。Mainメソッドには、コマンドライン引数をプログラムに渡すためのパラメータを指定できます。args : Array of String
キーワードを繰り返さずに、複数の型を宣言できますtype。
宣言されたメソッドの実装は、実装セクションに記述されます。
実装class method ConsoleApp.Main ; begin //ここに独自のコードを追加Console.WriteLine ( ' Hello World.' ) ; end ;終わり。ファイルは常に以下で終わりますend.
Oxygeneは.NET言語であるため、.NETの型システムを使用します。値型(構造体など)と参照型(配列やクラスなど)があります。
Oxygeneは独自の「事前定義」型を導入していませんが、それらのいくつかに対してより「パスカル風」の汎用名を提供しています[ 5 ]。たとえば、はSystem.Int32として使用できInteger、Boolean(System.Boolean)、Char(System.Char)、Real(System.Double)もパスカル型名のファミリーに加わります。これらの型の構造体特性(.NETの一部)は完全に保持されます。
すべての .NET 言語と同様に、Oxygene の型には可視性があります。Oxygene のデフォルトの可視性は でassembly、これはinternalC# の可視性に相当します。他に可能な型の可視性は ですpublic。
type MyClass = public class end ;可視性は、定義されているすべての型(クラス、インターフェース、レコードなど)に対して設定できます。
型にはエイリアス名を定義することができ、これはローカル環境または他のOxygeneアセンブリで使用できます。
type IntList = public List < Integer >; //他のOxygeneアセンブリから参照可能SecretEnumerable = IEnumerable < String >; //他のアセンブリからは参照不可公開された型エイリアスは、他の言語からは表示されません。
Oxygeneでは、.NET構造体はレコードと呼ばれます。レコードはクラスと同じように宣言されますが、recordキーワードが異なります。
type MyRecord = record method Foo ; end ;レコードは単なる.NET構造体であるため、フィールド、メソッド、プロパティを持つことはできますが、継承はできず、インターフェースを実装することもできません。
インターフェースは.NETの世界において非常に重要な概念であり、フレームワーク自体もインターフェースを多用しています。インターフェースとは、クラスがインターフェースを実装する際に実装しなければならない、少数のメソッド、プロパティ、およびイベントの仕様です。例えば、インターフェースはシーケンスを反復処理するために使用されるメソッドIEnumerable<T>を指定しますGetEnumerator。
インターフェースはクラスと同様に宣言されます。
type MyInterface = public interface method MakeItSo : IEnumerable ; property Bar : String read write ; end ;プロパティの場合、ゲッターとセッターは明示的に指定されていないことにご注意ください。
デリゲートはメソッドのシグネチャを定義するため、これらのメソッドをパラメータ(コールバックなど)として渡したり、変数に格納したりできます。デリゲートは、関数ポインタの型安全な.NET版です。また、イベントでも使用されます。メソッドをデリゲートに割り当てる際には、@コンパイラがメソッドを呼び出すのではなく、単に割り当てるだけであることを認識できるように、演算子を使用する必要があります。
Oxygeneは匿名デリゲートを作成できます。たとえば、Invokeデリゲートを宣言せずに、メソッドをコントロールのメソッドに渡すことができます。
method MainForm.MainForm_Load ( sender : System.Object ; e : System.EventArgs ) ; begin Invoke ( @DoSomething ) ; end ;DoSomethingコンパイラは、そのメソッドのシグネチャを持つ匿名デリゲートを作成します。
Oxygeneはポリモーフィックデリゲートをサポートしています。これは、降順型のパラメータを持つデリゲートは代入互換性があることを意味します。2つのクラスとMyClassがあると仮定するとMyClassEx = class(MyClass)、次のコードでははBlubbExと代入互換性がありますBlubb。
type delegate Blubb ( sender : Object ; m : MyClass ) ; delegate BlubbEx ( sender : Object ; mx : MyClassEx ) ;フィールドは、そのフィールドの型がインターフェースを実装している場合、インターフェースの実装を委任するために使用できます。
Implementor = public class ( IMyInterface ) // ... インターフェースを実装 ... end ;MyClass = public class ( IMyInterface ) fSomeImplementor : Implementor ; public implements IMyInterface ; //インターフェースの実装を担当しますend ;この例では、コンパイラは にパブリックなメソッドとプロパティを作成しMyClass、それらが のメソッド/プロパティを呼び出してfSomeImplementorIMyInterface のメンバーを実装します。これは、ミックスインのような機能を提供するために使用できます。[ 6 ]
匿名メソッドは、他のメソッドの内部で実装されます。デリゲートフィールドに格納されない限り、メソッドの外部からはアクセスできません。匿名メソッドは、実装されたメソッドのローカル変数と、所属するクラスのフィールドを使用できます。
匿名メソッドは、GUIスレッドで実行されるコードを扱う場合に特に便利です。これは、.NETではメソッドをメソッドに渡すことによって行われますInvoke(Control.InvokeWinFormsでは、Dispatcher.InvokeWPFでは)。
method Window1 . PredictNearFuture ; //インターフェースで非同期として宣言begin // ... ここで結果を計算し、変数 "theFuture" に格納しますDispatcher . Invoke ( DispatcherPriority . ApplicationIdle , method ; begin theFutureTextBox . Text := theFuture ; end ) ; end ;匿名メソッドもパラメータを持つことができます。
method Window1 . PredictNearFuture ; //インターフェースで非同期として宣言begin // ... ここで結果を計算し、変数 "theFuture" に格納しますDispatcher . Invoke ( DispatcherPriority . ApplicationIdle , method ( aFuture : String ) ; begin theFutureTextBox . Text := aFuture ; end , theFuture ) ; end ;どちらのソースコードも匿名デリゲートを使用しています。
プロパティ通知は主にデータバインディングで使用され、GUIがプロパティの値が変更されたことを知る必要がある場合に用いられます。.NETフレームワークは、この目的のためにインターフェイスINotifyPropertyChangedとINotifyPropertyChanging(.NET 3.5では)を提供しています。これらのインターフェイスは、プロパティが変更されたとき、または変更されたときに発生させる必要があるイベントを定義します。
Oxygeneはnotify、プロパティに使用できる修飾子を提供します。この修飾子を使用すると、コンパイラはクラスにインターフェースを追加し、それらを実装して、プロパティが変更されたとき、または変更されたときにイベントを発生させるコードを生成します。
property Foo : String read fFoo write SetFoo ; notify ; property Bar : String ; notify 'Blubb' ; // プロパティ "Bar" ではなく "Blubb" が変更されたことを通知しますこの修飾子は、セッターメソッドを持つプロパティに使用できます。イベントを発生させるコードは、コンパイル時にこのメソッドに追加されます。
名前空間HelloWorld ;インターフェースtype HelloClass = class public class method Main ; end ;実装class method HelloClass.Main ; begin writeLn ( ' Hello World!' ) ; end ;終わり。名前空間GenericContainer ;インターフェースtype TestApp = class public class method Main ; end ;Person = class public property FirstName : String ; property LastName : String ; end ;実装use System.Collections.Generic ;class method TestApp . Main ; begin var myList := new List < Person >; //型推論myList . Add ( new Person ( FirstName := 'John' , LastName := 'Doe' )) ; myList . Add ( new Person ( FirstName := 'Jane' , LastName := 'Doe' )) ; myList . Add ( new Person ( FirstName := 'James' , LastName := 'Doe' )) ; Console . WriteLine ( myList [ 1 ] . FirstName ) ; //キャストは不要Console . ReadLine ; end ;終わり。名前空間GenericMethodTest ;インターフェースtype GenericMethodTest = static class public class method Main ; private class method Swap < T > ( var left , right : T ) ; class method DoSwap < T > ( left , right : T ) ; end ;実装class method GenericMethodTest . DoSwap < T > ( left , right : T ) ; begin var a := left ; var b := right ; Console . WriteLine ( 'Type: {0}' , typeof ( T )) ; Console . WriteLine ( '-> a = {0}, b = {1}' , a , b ) ; Swap < T > ( var a , var b ) ; Console . WriteLine ( '-> a = {0}, b = {1}' , a , b ) ; end ;class method GenericMethodTest . Main ; begin var a := 23 ; // 型推論var b := 15 ; DoSwap < Integer > ( a , b ) ; // このメソッドでは Object へのダウンキャストは行いません。var aa := 'abc' ; // 型推論var bb := 'def' ; DoSwap < String > ( aa , bb ) ; // このメソッドでは Object へのダウンキャストは行いません。DoSwap ( 1.1 , 1.2 ) ; // ジェネリックパラメータの型推論Console . ReadLine () ; end ;class method GenericMethodTest . Swap < T > ( var left , right : T ) ; begin var temp := left ; left := right ; right := temp ; end ;終わり。プログラムの出力:
型: System.Int32 -> a = 23、b = 15 -> a = 15、b = 23 型: System.String -> a = abc、b = def -> a = def、b = abc 型: System.Double -> a = 1,1、b = 1,2 -> a = 1,2、b = 1,1
unit: namespaceキーワードに置き換えられました。Oxygene はファイル単位ではなくプロジェクト単位でコンパイルするため、ファイル名に依存しません。代わりに、unit または namespace キーワードを使用して、そのファイル内のすべての型が定義されているデフォルトの名前空間を指定します。procedurefunction:がmethod推奨キーワードですが、procedureとfunctionも引き続き機能します。overloadOxygeneでは、すべてのメソッドがデフォルトでオーバーロードされているため、特別なキーワードは必要ありません。.Create()このコンストラクタ呼び出しはキーワードに置き換えられました。互換性の理由newから、引き続き有効にすることができます。project optionsstring文字列内の文字は0から始まり、読み取り専用です。文字列にはnil値が含まれる可能性があるため、空文字列との比較だけでは十分でない場合があります。Win32 Delphi コードを大きな変更を加えずに Oxygene に移植したいと考える人もいるでしょう。しかし、Oxygene は Delphi に似ていますが、単純な再コンパイルでは互換性がなくなるほどの変更が加えられているため、これは不可能です。名前から Delphi の別のバージョンであるかのように見えますが、それは完全に正しいとは言えません。[ 7 ]
言語の違いに加えて、 Oxygene ではVisual Component Libraryフレームワークが利用できません。[ 8 ]従来の Delphi コードは VCL に大きく依存しているため、移植はさらに困難になります。