Oxygene (język programowania)
Deweloper | Oprogramowanie RemObjects |
---|---|
Po raz pierwszy pojawiły się | 2005 |
Platforma | Common Language Infrastructure , Java , Cocoa , CPU-Native, Windows 32/64-bitowy, Linux 32/64-bitowy, WebAssembly |
Licencja | Wersja próbna |
Strona internetowa | |
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
ifunkcja
:metoda
jest preferowanym słowem kluczowym, chociażprocedura
ifunkcja
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 kluczowymnew
. Nadal można go włączyć wopcjach 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.