Oxygene (język programowania)

tlen
Chrome-128.png
Deweloper Oprogramowanie RemObjects
Po raz pierwszy pojawiły się 2005 ; 18 lat temu ( 2005 )
Platforma Common Language Infrastructure , Java , Cocoa , CPU-Native, Windows 32/64-bitowy, Linux 32/64-bitowy, WebAssembly
Licencja Wersja próbna
Strona internetowa elementykompilator.com/elementy/oksygen/ _ _ _ _
Pod wpływem
Delphi's Object Pascal , C#

Oxygene (wcześniej znany jako Chrome ) to język programowania opracowany przez RemObjects Software dla Common Language Infrastructure firmy Microsoft , platformy Java i Cocoa . Oxygene jest oparty na Delphi 's Object Pascal , ale ma również wpływy z C# , Eiffel , Java , F# i innych języków.

W porównaniu z obecnie przestarzałym Delphi.NET , Oxygene nie kładzie nacisku na całkowitą kompatybilność wsteczną, ale został zaprojektowany jako „ponowne wynalezienie” języka, bycie dobrym obywatelem na zarządzanych platformach programistycznych oraz wykorzystanie wszystkich funkcji i technologii dostarczonych przez Środowisko wykonawcze .NET i Java.

Oxygene jest produktem komercyjnym i oferuje pełną integrację ze środowiskiem Microsoft Visual Studio IDE w systemie Windows, a także własnym środowiskiem IDE o nazwie Fire do użytku w systemie macOS . 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 (oparty na Visual Basic.NET ).

W latach 2008-2012 firma RemObjects Software udzielała licencji na swój kompilator i technologię IDE firmie Embarcadero do użytku w ich Embarcadero Prism produkt. Począwszy od jesieni 2011 roku, 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 umożliwiających migrację do Oxygene. Od 2016 roku istnieje tylko jedna edycja Oxygene, która umożliwia programowanie w systemie Windows lub macOS i może tworzyć pliki wykonywalne dla systemów Windows, Linux, WebAssembly .NET, iOS, Android, Java i macOS.

Język

Język Oxygene wywodzi się ogólnie z Object Pascal, aw szczególności z Delphi, ale został zaprojektowany tak, aby odzwierciedlał wytyczne programowania .NET i tworzył asemblery w pełni zgodne z CLR. Dlatego niektóre pomniejsze funkcje języka znane z Object Pascal / Delphi zostały usunięte lub poprawione, podczas gdy do języka dodano mnóstwo nowych i bardziej nowoczesnych funkcji, takich jak generyczne lub sekwencje i zapytania.

Oxygene jest językiem zorientowanym obiektowo , co oznacza, że ​​do projektowania programów używa klas, które mogą przechowywać dane i wykonywać kod. [ potrzebne wyjaśnienie ] Klasy są „prototypami” obiektów, podobnie jak idea jabłka jest prototypem jabłka, które można faktycznie kupić w sklepie. Wiadomo, że jabłko ma kolor i że można je obrać: to są dane i wykonywalny „kod” dla klasy jabłek.

Oxygene zapewnia wsparcie na poziomie języka dla niektórych funkcji programowania równoległego. Celem jest wykorzystanie wszystkich rdzeni lub procesorów komputera w celu poprawy wydajności. Aby osiągnąć ten cel, zadania muszą być rozdzielone między kilka wątków. Klasa ThreadPool platformy .NET Framework umożliwia efektywną pracę z kilkoma wątkami. Biblioteka zadań równoległych (TPL) została wprowadzona w programie .NET 4,0, aby zapewnić więcej funkcji programowania równoległego.

Operatory mogą być przeciążane w Oxygene przy użyciu składni operatora klasy :

       niejawny  operator  klasy  (  i  :  Integer  )  :  MyClass  ; 

Zauważ, że dla przeciążania operatorów każdy operator ma swoją nazwę, która musi być użyta w składni przeciążania operatorów, ponieważ np. "+" nie byłoby prawidłową nazwą metody w Oxygene.

Struktura programu

Oxygene nie używa „jednostek”, jak 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 z jednej przestrzeni nazw. Ta przestrzeń nazw jest zdefiniowana na samej górze pliku:

przestrzeń nazw ConsoleAplikacja1;

Pliki Oxygene podzielone są na interfejs i sekcję implementacyjną, która jest strukturą znaną z Delphi. Sekcja interfejsu następuje po deklaracji przestrzeni nazw. Zawiera using , która w Oxygene importuje typy z innych przestrzeni nazw:


   korzysta z  Systemu  .  Linq  ; 

Zaimportowane przestrzenie nazw muszą znajdować się w samym projekcie lub w przywoływanych zestawach. Inaczej niż w C#, w Oxygene nie można definiować nazw aliasów dla przestrzeni nazw, tylko dla nazw pojedynczych typów (patrz poniżej).

Po klauzuliuses plik zawiera deklaracje typu, takie jakie są znane z Delphi:




    
  
      
   typ  interfejsu  ConsoleApp  =  class  public  class  method  Main  ;  koniec  ; 

Podobnie jak w języku 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 słowa kluczowego type .

Implementację zadeklarowanych metod umieszczamy w sekcji implementacji:



  

  
  


 metoda  klasy  implementacji  ConsoleApp  .  Główny  ;  begin  // dodaj tutaj swój własny kod  Console  .  WriteLine  (  'Witaj świecie.'  )  ;  koniec  ;  koniec  . 

Pliki zawsze kończą się końcem.

typy

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 bardziej „pascalowe” nazwy generyczne dla niektórych z nich, dzięki czemu na przykład System.Int32 może być używany jako Integer i Boolean ( System.Boolean ), Char ( System .Char ), Real ( System.Double ) również dołączają do rodziny nazw typów pascalowych. 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ślną widocznością jest assembly , która odpowiada wewnętrznej widoczności w C#. Inną możliwą widocznością typu jest public .


     
 wpisz  MojaKlasa  =  koniec  klasy  publicznej  ; 

Widoczność można ustawić dla każdego zdefiniowanego typu (klasy, interfejsy, rekordy, ...).

Dla typów można zdefiniować alias, który może być używany lokalnie lub w innych zespołach Oxygene.


      
      wpisz  IntList  =  lista  publiczna  <  liczba całkowita  >;  //widoczne w innych zespołach Oxygene  SecretEnumerable  =  IEnumerable  <  String  >;  //niewidoczne w innych zespołach 

Aliasy typów publicznych nie będą widoczne dla innych języków.

Dokumentacja

Rekordy są nazywane strukturami .NET w Oxygene. Deklaruje się je tak samo jak klasy, ale za pomocą record :


    
     
   wpisz  MyRecord  =  metoda  zapisu  Foo  ;  koniec  ; 

Ponieważ są to tylko struktury .NET, rekordy mogą zawierać 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 metodę GetEnumerator , która jest używana do iteracji po sekwencjach.

Interfejsy są deklarowane podobnie jak klasy:


     
       
         
   wpisz  MyInterface  =  metoda  publicznego  interfejsu  MakeItSo  :  IEnumerable  ;  właściwość  Bar  :  Ciąg  odczyt  i zapis  ;  koniec  ; 

Proszę zauważyć, że dla właściwości getter i setter nie są jawnie określone.

Delegaci

Delegaci definiują sygnatury dla metod, dzięki czemu metody te mogą być przekazywane w parametrach (np. wywołania zwrotne) lub przechowywane w zmiennych itp. Są one bezpiecznym typem NET-owym odpowiednikiem wskaźników funkcji. Są również używane na imprezach. Przypisując metodę do delegata, należy użyć @ , 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 kontrolki bez deklarowania delegata:


  
     Metoda  MainForm  .  MainForm_Load  (  nadawca  :  System  .  Obiekt  ;  e  :  System  .  EventArgs  )  ; 
 rozpocząć  Invoke  (  @  DoCoś  )  ;  koniec  ; 

Kompilator utworzy anonimowego delegata z sygnaturą metody DoSomething .

Oxygene obsługuje delegatów polimorficznych, co oznacza, że ​​delegaci, którzy mają parametry typu malejącego, są kompatybilni z przypisaniami. Załóżmy, że dwie klasy MyClass i MyClassEx = class(MyClass) , a następnie w poniższym kodzie BlubbEx jest przypisaniem zgodnym z Blubb .


        
         wpisz  delegata  Blubb  (  nadawca  :  obiekt  ;  m  :  moja klasa  )  ;  delegat  BlubbEx  (  nadawca  :  obiekt  ;  mx  :  MyClassEx  )  ; 

Pola mogą służyć do delegowania implementacji interfejsu, jeśli typ, którego są, implementuje ten interfejs:

   
  


   
        
 Implementor  =  public  class  (  IMyInterface  )  //...implement interface...  end  ;  MyClass  =  klasa  publiczna  (  IMyInterface  )  fSomeImplementor  :  Implementor  ;  public  implementuje  IMyInterface  ;  //zajmuje się implementacją  końca interfejsu   ; 

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 miksu.

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 metody Invoke ( Control.Invoke w WinForms , Dispatcher.Invoke w WPF):


  
      
        
    
    metoda  Okno1  .  Przewidywanie bliskiej przyszłości  ;  //zadeklarowany jako asynchroniczny w interfejsie 
 begin  // ... Oblicz wynik tutaj, przechowuj w zmiennej „theFuture”  Dispatcher  .  Invoke  (  DispatcherPriority  .  ApplicationIdle  ,  method  ;  begin  theFutureTextBox  .  Text  :=  theFuture  ;  end  )  ;  koniec  ; 

Metody anonimowe również mogą mieć parametry:


  
        
          metoda  Okno1  .  Przewidywanie bliskiej przyszłości  ;  //zadeklarowany jako asynchroniczny w interfejsie 
 begin  // ... Oblicz wynik tutaj, przechowuj w zmiennej „theFuture”  Dispatcher  .  Invoke  (  DispatcherPriority  .  ApplicationIdle  ,  method  (  aFuture  :  String  )  ;  start  theFutureTextBox.Text  :  =  aFuture  ;  end  ,  theFuture  )  ;  _    
     
 koniec  ; 

Oba kody źródłowe używają anonimowych delegatów .

Zgłoszenie nieruchomości

Powiadomienie o właściwościach jest używane głównie do powiązania danych, gdy GUI musi wiedzieć, kiedy zmienia się wartość właściwości. Platforma .NET udostępnia w tym celu interfejsy INotifyPropertyChanged i INotifyPropertyChanging (w .NET 3,5). Te interfejsy definiują zdarzenia, które muszą zostać uruchomione, gdy właściwość zostanie zmieniona / została zmieniona.

Oxygene zapewnia modyfikator powiadamiania , którego można użyć we właściwościach. Jeśli ten modyfikator zostanie użyty, kompilator doda interfejsy do klasy, zaimplementuje je i utworzy kod wywołujący zdarzenia, gdy właściwość się zmieni / została zmieniona.

        
       właściwość  Foo  :  String  odczyt  fFoo  zapis  SetFoo  ;  powiadomić  ;  właściwość  Pasek  :  Ciąg znaków  ;  powiadomić  „Blubb”  ;  //powiadomi, że właściwość „Blubb” została zmieniona zamiast „Bar” 

Modyfikatora można użyć na właściwościach, które mają metodę ustawiającą. Kod wywołujący zdarzenia zostanie następnie dodany do tej metody w czasie kompilacji.

Przykłady kodu

Witaj świecie





    
  
      
  



  

  


  przestrzeń nazw  HelloWorld  ; 
 typ  interfejsu  HelloClass  =  class  public  class  method  Main  ;  koniec  ;  metoda  klasy  implementacji  HelloClass  .  Główny  ;  zacznij  pisaćLn  (  'Witaj świecie!'  )  ;  koniec  ;  koniec  . 

Ogólny pojemnik





    
  
      
  

    
  
      
           
  




  

  przestrzeń nazw  GenericContainer  ; 
 typ  interfejsu  TestApp  =  class  public  class  method  Main  ;  koniec  ;  Person  =  class  właściwość  publiczna  Imię  :  String  ;  właściwość  Nazwisko  :  String  ;  koniec  ;  implementacja  wykorzystuje  System  .  Kolekcje  .  ogólny  ;  metoda  klasowa   

       
         
      aplikacja testowa  .  Główny  ;  begin  var  mojaLista  :=  nowa  Lista  <  Osoba  >;  //wpisz wnioskowanie  myList  .  Dodaj  (  nowa  osoba  (  Imię  :=  'Jan'  ,  Nazwisko  :=  'Kowalski'  ))  ;  mojaLista  .  Dodaj  (  nowa  Osoba  (  Imię  :=  'Jane'  ,    
         
    
         


 Nazwisko  :=  'Kowalski'  ))  ;  mojaLista  .  Dodaj  (  nowa  osoba  (  Imię  :=  'James'  ,  Nazwisko  :=  'Kowalski'  ))  ;  Konsola  .  WriteLine  (  myList  [  1  ]  .Imię  )  ;  _  //Nie jest wymagane przesyłanie  Konsola  .  Odczyt wiersza  ;  koniec  ;  koniec  . 

Metoda ogólna





   

    

        
         przestrzeń nazw  GenericMethodTest  ; 
 typ  interfejsu  GenericMethodTest  =  klasa  statyczna  metoda  klasy  publicznej  Main  ;  metoda  klasy  prywatnej  Swap  <T>  (  var  left  ,  right  :  T  )  ;  _  _  metoda  klasy  DoSwap  <  T  >  (  lewa  ,  prawa  :  T  ) 




     

     
     
   
   ;  koniec  ;  metoda  klasy  implementacji  GenericMethodTest  .  DoSwap  <T>  (  lewo  ,  prawo  :  T  )  ;  _  _  rozpocznij  var  a  :=  lewo  ;  var  b  :=  dobrze  ;  Konsola  .  WriteLine  (  'Typ: {0}'  ,  typ  (  T  ))  ;  Konsola  .    
     
     


  

    WriteLine  (  '-> a = {0}, b = {1}'  ,  a  ,  b  )  ;  Zamień  <T>  (  zmienna  a  ,  zmienna  b  )  ;  _  _  Konsola  .  WriteLine  (  '-> a = {0}, b = {1}'  ,  a  ,  b  )  ;  koniec  ;  Metoda  klasowa  GenericMethodTest  .  Główny  ;  rozpocząć  var  ​​a   
     
    

     
     
    :=  23  ;  // wnioskowanie typu  var  b  :=  15  ;  DoSwap  <  liczba całkowita  >  (  a  ,  b  )  ;  // brak rzutowania w dół na obiekt w tej metodzie.  var  aa  :=  'abc'  ;  // wnioskowanie typu  var  bb  :=  'def'  ;  DoSwap  <  Ciąg  >  (  aa  ,  bb  )  ;  

    
  


      

     
   // brak rzutowania w dół na obiekt w tej metodzie.  DoSwap  (  1.1  ,  1.2  )  ;  // wnioskowanie typu dla parametrów ogólnych  Console  .  Odczyt wiersza  ()  ;  koniec  ;  Metoda  klasowa  GenericMethodTest  .  Zamień  <  T  >  (  var  w lewo  ,  w prawo  :  T  )  ;  rozpocznij  var  temp  :=  lewo  ;  w lewo  :=  
    


 dobrze  ;  dobrze  :=  temp  ;  koniec  ;  koniec  . 

Wyjście programu:

Typ: System.Int32 -> a = 23, b = 15 -> a = 15, b = 23 Typ: System.String -> a = abc, b = def -> a = def, b = abc Typ: System. Podwójne -> a = 1,1, b = 1,2 -> a = 1,2, b = 1,1

Różnice między Delphi i Oxygene

  • unit : Zastąpione słowem kluczowym przestrzeni nazw . Ponieważ Oxygene nie kompiluje dla pliku, ale dla projektu, nie zależy to od nazwy pliku. Zamiast tego słowo kluczowe unit lub namespace jest używane do określenia domyślnej przestrzeni nazw, w której zdefiniowane są wszystkie typy dla tego pliku
  • procedura i funkcja : metoda jest preferowanym słowem kluczowym, 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
  • string : Znaki w ciągach są liczone od zera i tylko do odczytu. Ciągi mogą mieć wartości zerowe, więc testowanie na pustym łańcuchu nie zawsze jest wystarczające.

Krytyka

Niektórzy ludzie [ kto? ] chciałby 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 przy prostej rekompilacji. Chociaż nazwa nadaje mu wygląd innej wersji Delphi, nie jest to do końca prawdą.

Poza różnicą językową, struktura Visual Component Library nie jest dostępna w Oxygene. To sprawia, że ​​przenoszenie jest jeszcze trudniejsze, ponieważ klasyczny kod Delphi w dużym stopniu opiera się na VCL.

Zobacz też

Linki zewnętrzne