Tlen (język programowania) - Oxygene (programming language)

Tlen
Chrome-128.png
Deweloper Oprogramowanie RemObjects
Po raz pierwszy pojawiły się 2005 ; 16 lat temu ( 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 kompilator elementów .com /elementy /tlen /
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 ThreadPoolklasa 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 operatorskł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 usesklauzulę, 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 usesklauzuli 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 Stringdo przekazywania argumentów wiersza poleceń do programu.

Więcej typów można zadeklarować bez powtarzania typesł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.Int32mogą być używane jako Integeri 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 internalwidocznoś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 recordsł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 GetEnumeratormetodę, 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 Invokemetody kontrolki bez deklarowania delegata:

method MainForm.MainForm_Load(sender: System.Object; e: System.EventArgs);
begin
  Invoke(@DoSomething);
end;

DoSomethingKompilator 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 MyClassi MyClassEx = class(MyClass), a następnie w poniższym kodzie BlubbExprzypisanie 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 Invokemethod ( Control.Invokew WinForms, Dispatcher.Invokew 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 INotifyPropertyChangedi 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 notifymodyfikatora, 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.

Zobacz też

Bibliografia

Linki zewnętrzne