Tlen (język programowania) - Oxygene (programming language)
Deweloper | Oprogramowanie RemObjects |
---|---|
Po raz pierwszy pojawiły się | 2005 |
Platforma | Infrastruktura wspólnego języka , Java , Cocoa , natywna dla procesora, Windows 32/64-bitowy, Linux 32/64-bitowy, WebAssembly |
Licencja | Wersja próbna |
Stronie internetowej | |
Wpływem | |
Delphi jest obiekt Pascal , C # |
Oxygene (wcześniej znany jako Chrome ) to język programowania opracowany przez RemObjects Software dla wspólnej infrastruktury językowej firmy Microsoft , platformy Java i Cocoa . Oxygene opiera się na Delphi jest Object Pascal , ale ma również wpływy z C # , Eiffel , Java , F # oraz innych językach.
W porównaniu do obecnie przestarzałego Delphi.NET , Oxygene nie kładzie nacisku na całkowitą kompatybilność wsteczną, ale ma na celu „przeprojektowanie” języka, bycie dobrym obywatelem na zarządzanych platformach programistycznych i wykorzystanie wszystkich funkcji i technologii zapewnianych przez Środowiska wykonawcze .NET i Java.
Oxygene jest produktem handlowym i oferuje pełną integrację z Microsoft „s Visual Studio IDE w systemie Windows, jak również jego własny IDE o nazwie ogień do stosowania na MacOS . Kompilator wiersza poleceń jest dostępny za darmo. Oxygene jest jednym z sześciu języków obsługiwanych przez podstawowy zestaw narzędzi Elements Compiler, obok C# , Swift , Java , Go i Mercury (opartego na Visual Basic.NET ).
W latach 2008-2012 firma RemObjects Software udzielała licencji Embarcadero na swój kompilator i technologię IDE do wykorzystania w produkcie Embarcadero Prism . Od jesieni 2011 r. Oxygene stał się dostępny w dwóch oddzielnych edycjach, przy czym druga edycja dodała obsługę środowisk wykonawczych Java i Android. Począwszy od wydania XE4, Embarcadero Prism nie jest już częścią RAD Studio SKU. Istnieje wiele ścieżek wsparcia i aktualizacji dla klientów Prism w celu migracji do Oxygene. Od 2016 roku istnieje tylko jedna edycja Oxygene, która umożliwia programowanie w systemie Windows lub macOS i która może tworzyć pliki wykonywalne dla systemów Windows, Linux, WebAssembly .NET, iOS, Android, Java i macOS.
Język
Język Oxygene ma swoje początki ogólnie w Object Pascal, aw szczególności Delphi, ale został zaprojektowany tak, aby odzwierciedlać wytyczne programowania .NET i tworzyć w pełni zgodne z CLR zespoły. Dlatego też niektóre pomniejsze funkcje językowe znane z Object Pascal / Delphi zostały porzucone lub poprawione, podczas gdy do języka dodano mnóstwo nowych i bardziej nowoczesnych funkcji, takich jak Generics lub Sequences and Queries.
Oxygene jest językiem zorientowanym obiektowo , co oznacza, że do projektowania programów używa klas, które mogą przechowywać dane i wykonywać kod. Klasy są "prototypami" przedmiotów, tak jak idea jabłka jest prototypem jabłka, które faktycznie można kupić w sklepie. Wiadomo, że jabłko ma kolor i że można je obrać: to są dane i wykonywalny "kod" klasy jabłek.
Oxygene zapewnia obsługę niektórych funkcji programowania równoległego na poziomie języka. Celem jest wykorzystanie wszystkich rdzeni lub procesorów komputera w celu poprawy wydajności. Aby osiągnąć ten cel, zadania muszą być rozdzielone na kilka wątków. Framework „s ThreadPool
klasa oferowana sposób na efektywną pracę z kilkoma wątkami. Task Parallel Library (TPL) został wprowadzony w .NET 4.0, aby zapewnić więcej możliwości do programowania równoległego.
Operatory można przeciążać w Oxygene za pomocą class operator
składni:
class operator implicit(i : Integer) : MyClass;
Zauważ, że dla przeciążenia operatora każdy operator ma swoją nazwę, która musi być użyta w składni przeciążenia operatora, ponieważ na przykład "+" nie byłoby poprawną nazwą metody w Oxygene.
Struktura programu
Oxygene nie używa "jednostek", jak robi to Delphi, ale używa przestrzeni nazw .NET do organizowania i grupowania typów. Przestrzeń nazw może obejmować wiele plików (i zestawów), ale jeden plik może zawierać tylko typy jednej przestrzeni nazw. Ta przestrzeń nazw jest zdefiniowana na samej górze pliku:
namespace ConsoleApplication1;
Pliki Oxygene podzielone są na interfejs i sekcję implementacyjną, czyli strukturę znaną z Delphi. Sekcja interfejsu jest zgodna z deklaracją przestrzeni nazw. Zawiera uses
klauzulę, która w Oxygene importuje typy z innych przestrzeni nazw:
uses
System.Linq;
Importowane przestrzenie nazw muszą znajdować się w samym projekcie lub w zestawach, do których istnieją odniesienia. W przeciwieństwie do C#, w Oxygene aliasy nie mogą być definiowane dla przestrzeni nazw, tylko dla pojedynczych typów nazw (patrz poniżej).
Po uses
klauzuli plik zawiera deklaracje typów, takie jak znane z Delphi:
interface
type
ConsoleApp = class
public
class method Main;
end;
Podobnie jak w C#, metoda Main jest punktem wejścia dla każdego programu. Może mieć parametr args : Array of String
do przekazywania argumentów wiersza poleceń do programu.
Więcej typów można zadeklarować bez powtarzania type
słowa kluczowego.
Implementacja zadeklarowanych metod znajduje się w sekcji implementacja:
implementation
class method ConsoleApp.Main;
begin
// add your own code here
Console.WriteLine('Hello World.');
end;
end.
Pliki są zawsze zakończone end.
Rodzaje
Jako język .NET, Oxygene używa systemu typów .NET: istnieją typy wartości (takie jak struktury) i typy referencyjne (takie jak tablice lub klasy).
Chociaż nie wprowadza własnych „predefiniowanych” typów, Oxygene oferuje dla niektórych z nich bardziej „pascalowe” nazwy ogólne, tak że na przykład System.Int32
mogą być używane jako Integer
i Boolean
( System.Boolean
), Char
( System.Char
), Real
( System.Double
) dołączają do rodziny pascal- również nazwy typów. Charakter struktury tych typów, który jest częścią platformy .NET, jest w pełni zachowany.
Jak we wszystkich językach .NET, typy w Oxygene mają widoczność. W Oxygene domyślna widoczność to assembly
, która jest odpowiednikiem internal
widoczności w C#. Inną możliwą widocznością typu jest public
.
type
MyClass = public class
end;
Widoczność można ustawić dla każdego zdefiniowanego typu (klasy, interfejsy, rekordy, ...).
Nazwę aliasu można zdefiniować dla typów, które mogą być używane lokalnie lub w innych zestawach Oxygene.
type
IntList = public List<Integer>; //visible in other Oxygene-assemblies
SecretEnumerable = IEnumerable<String>; //not visible in other assemblies
Aliasy typu publicznego nie będą widoczne dla innych języków.
Dokumentacja
Rekordy to tak zwane struktury .NET w Oxygene. Są deklarowane tak jak klasy, ale ze record
słowem kluczowym:
type
MyRecord = record
method Foo;
end;
Ponieważ są to tylko struktury .NET, rekordy mogą mieć pola, metody i właściwości, ale nie mają dziedziczenia i nie mogą implementować interfejsów .
Interfejsy
Interfejsy są bardzo ważną koncepcją w świecie .NET, sam framework intensywnie z nich korzysta. Interfejsy to specyfikacja małego zestawu metod, właściwości i zdarzeń, które klasa musi zaimplementować podczas implementacji interfejsu. Na przykład interfejs IEnumerable<T>
określa GetEnumerator
metodę, która jest używana do iteracji po sekwencjach.
Interfejsy są deklarowane tak jak klasy:
type
MyInterface = public interface
method MakeItSo : IEnumerable;
property Bar : String read write;
end;
Proszę zauważyć, że dla właściwości metody pobierające i ustawiające nie są wyraźnie określone.
Delegaci
Delegaci definiują sygnatury metod, dzięki czemu te metody mogą być przekazywane w parametrach (np. wywołania zwrotne) lub przechowywane w zmiennych itp. Są one bezpiecznym dla typu odpowiednikiem NET wskaźników do funkcji. Są również używane w wydarzeniach. Przypisując metodę do delegata, należy użyć @
operatora, aby kompilator wiedział, że nie chce się wywoływać metody, tylko ją przypisać.
Oxygene może tworzyć anonimowych delegatów; na przykład metody można przekazać do Invoke
metody kontrolki bez deklarowania delegata:
method MainForm.MainForm_Load(sender: System.Object; e: System.EventArgs);
begin
Invoke(@DoSomething);
end;
DoSomething
Kompilator utworzy anonimowy delegat z podpisem metody .
Oxygene obsługuje delegacje polimorficzne, co oznacza, że delegacje posiadające parametry typu malejącego są zgodne z przypisaniami. Załóżmy dwie klasy MyClass
i MyClassEx = class(MyClass)
, a następnie w poniższym kodzie BlubbEx
przypisanie jest zgodne z Blubb
.
type
delegate Blubb(sender : Object; m : MyClass);
delegate BlubbEx(sender : Object; mx : MyClassEx);
Pola mogą służyć do delegowania implementacji interfejsu, jeśli ich typ implementuje ten interfejs:
Implementor = public class(IMyInterface)
// ... implement interface ...
end;
MyClass = public class(IMyInterface)
fSomeImplementor : Implementor; public implements IMyInterface; //takes care of implementing the interface
end;
W tym przykładzie kompilator utworzy publiczne metody i właściwości w MyClass
, które wywołują metody/właściwości fSomeImplementor
, aby zaimplementować elementy członkowskie IMyInterface. Można to wykorzystać do zapewnienia funkcjonalności podobnej do mixin.
Metody anonimowe
Metody anonimowe są implementowane wewnątrz innych metod. Nie są dostępne poza metodą, chyba że są przechowywane w polu delegata. Metody anonimowe mogą używać zmiennych lokalnych metody, w której są zaimplementowane, oraz pól klasy, do której należą.
Metody anonimowe są szczególnie przydatne podczas pracy z kodem, który ma być wykonywany w wątku GUI, co odbywa się w .NET poprzez przekazanie metody do the Invoke
method ( Control.Invoke
w WinForms, Dispatcher.Invoke
w WPF):
method Window1.PredictNearFuture; //declared as async in the interface
begin
// ... Calculate result here, store in variable "theFuture"
Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, method; begin
theFutureTextBox.Text := theFuture;
end);
end;
Metody anonimowe mogą mieć również parametry:
method Window1.PredictNearFuture; //declared as async in the interface
begin
// ... Calculate result here, store in variable "theFuture"
Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, method(aFuture : String); begin
theFutureTextBox.Text := aFuture ;
end, theFuture);
end;
Oba kody źródłowe używają anonimowych delegatów .
Powiadomienie o nieruchomości
Powiadomienie o właściwościach jest używane głównie do wiązania danych, gdy GUI musi wiedzieć, kiedy zmienia się wartość właściwości. .NET Framework udostępnia interfejsy INotifyPropertyChanged
i INotifyPropertyChanging
(w .NET 3.5) do tego celu. Te interfejsy definiują zdarzenia, które muszą zostać wywołane, gdy właściwość zostanie zmieniona / zmieniona.
Tlen dostarcza notify
modyfikatora, którego można używać na właściwościach. Jeśli ten modyfikator zostanie użyty, kompilator doda interfejsy do klasy, zaimplementuje je i utworzy kod, który wywoła zdarzenia, gdy właściwość zmieni się / została zmieniona.
property Foo : String read fFoo write SetFoo; notify;
property Bar : String; notify 'Blubb'; //will notify that property "Blubb" was changed instead of "Bar"
Modyfikatora można używać we właściwościach, które mają metodę ustawiającą. Kod do wywołania zdarzeń zostanie następnie dodany do tej metody w czasie kompilacji.
Przykłady kodu
Witaj świecie
namespace HelloWorld;
interface
type
HelloClass = class
public
class method Main;
end;
implementation
class method HelloClass.Main;
begin
System.Console.WriteLine('Hello World!');
end;
end.
Kontener ogólny
namespace GenericContainer;
interface
type
TestApp = class
public
class method Main;
end;
Person = class
public
property FirstName: String;
property LastName: String;
end;
implementation
uses
System.Collections.Generic;
class method TestApp.Main;
begin
var myList := new List<Person>; //type inference
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); //No casting needed
Console.ReadLine;
end;
end.
Metoda ogólna
namespace GenericMethodTest;
interface
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;
implementation
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;// type inference
var b := 15;
DoSwap<Integer>(a, b); // no downcasting to Object in this method.
var aa := 'abc';// type inference
var bb := 'def';
DoSwap<String>(aa, bb); // no downcasting to Object in this method.
DoSwap(1.1, 1.2); // type inference for generic parameters
Console.ReadLine();
end;
class method GenericMethodTest.Swap<T>(var left, right : T);
begin
var temp := left;
left:= right;
right := temp;
end;
end.
Wyjście programu:
Type: System.Int32 -> a = 23, b = 15 -> a = 15, b = 23 Type: System.String -> a = abc, b = def -> a = def, b = abc Type: System.Double -> a = 1,1, b = 1,2 -> a = 1,2, b = 1,1
Różnice między Delphi a Oxygene
- unit : Zastąpione słowem kluczowym przestrzeni nazw . Ponieważ Oxygene nie kompiluje na plik, ale na projekt, nie zależy od nazwy pliku. Zamiast tego słowo kluczowe unit lub namespace jest używane do oznaczenia domyślnej przestrzeni nazw, w której zdefiniowane są wszystkie typy dla tego pliku
- procedura i funkcja : preferowanym słowem kluczowym jest metoda , chociaż procedura i funkcja nadal działają.
- przeciążenie : W Oxygene wszystkie metody są domyślnie przeciążone, więc nie jest do tego potrzebne żadne specjalne słowo kluczowe
- .Create() : To wywołanie konstruktora zostało zastąpione słowem kluczowym new . Nadal można go włączyć w opcjach projektu ze względu na starsze przyczyny
- ciąg : znaki w ciągach są liczone od zera i tylko do odczytu. Łańcuchy mogą mieć zerowe wartości, więc testowanie z pustym łańcuchem nie zawsze jest wystarczające.
Krytyka
Niektórzy ludzie chcieliby przenieść swój kod Win32 Delphi do Oxygene bez wprowadzania większych zmian. Nie jest to możliwe, ponieważ chociaż Oxygene wygląda jak Delphi, jest wystarczająco dużo zmian, aby uczynić go niekompatybilnym dla prostej rekompilacji. Chociaż nazwa nadaje mu wygląd innej wersji Delphi, nie jest to do końca prawda.
Oprócz różnic językowych, platforma Visual Component Library nie jest dostępna w Oxygene. To sprawia, że portowanie jest jeszcze trudniejsze, ponieważ klasyczny kod Delphi w dużym stopniu opiera się na VCL.