Oxygene (linguaggio di programmazione) - Oxygene (programming language)

ossigeno
Chrome-128.png
Sviluppatore Software RemObjects
Apparso per la prima volta 2005 ; 16 anni fa ( 2005 )
piattaforma Common Language Infrastructure , Java , Cocoa , CPU-Native, Windows 32/64 bit, Linux 32/64 bit, WebAssembly
Licenza Software di prova
Sito web elementcompiler .com /elements /oxygene /
Influenzato da
Delphi s' Object Pascal , C #

Oxygene (precedentemente noto come Chrome ) è un linguaggio di programmazione sviluppato da RemObjects Software per Common Language Infrastructure di Microsoft , Java Platform e Cocoa . Oxygene è basata su Delphi s' Object Pascal , ma ha anche influenze da C # , Eiffel , Java , C # e altri linguaggi.

Rispetto all'ormai deprecato Delphi.NET , Oxygene non enfatizza la totale compatibilità con le versioni precedenti, ma è progettato per essere una "reinvenzione" del linguaggio, essere un buon cittadino sulle piattaforme di sviluppo gestite e sfruttare tutte le funzionalità e le tecnologie fornite dal Runtime .NET e Java.

Oxygene è un prodotto commerciale e offre la piena integrazione in Microsoft 's Visual Studio IDE di Windows, così come la sua propria IDE chiamato Fuoco per l'uso su MacOS . Il compilatore da riga di comando è disponibile gratuitamente. Oxygene è uno dei sei linguaggi supportati dalla sottostante toolchain Elements Compiler, accanto a C# , Swift , Java , Go e Mercury (basato su Visual Basic.NET ).

Dal 2008 al 2012, RemObjects Software ha concesso in licenza il proprio compilatore e la tecnologia IDE a Embarcadero da utilizzare nel prodotto Embarcadero Prism . A partire dall'autunno del 2011, Oxygene è diventato disponibile in due edizioni separate, con la seconda edizione che ha aggiunto il supporto per i runtime Java e Android. A partire dal rilascio di XE4, Embarcadero Prism non fa più parte della SKU di RAD Studio. Esistono numerosi percorsi di supporto e aggiornamento per i clienti Prism per migrare a Oxygene. A partire dal 2016, esiste una sola edizione di Oxygene, che consente lo sviluppo su Windows o macOS e che può creare eseguibili per Windows, Linux, WebAssembly .NET, iOS, Android, Java e macOS.

La lingua

Il linguaggio Oxygene ha le sue origini in Object Pascal in generale e Delphi in particolare, ma è stato progettato per riflettere le linee guida della programmazione .NET e per creare assembly completamente conformi a CLR. Pertanto, alcune funzionalità del linguaggio minori note da Object Pascal / Delphi sono state eliminate o riviste, mentre sono state aggiunte al linguaggio una serie di funzionalità nuove e più moderne, come Generics o Sequences and Queries.

Oxygene è un linguaggio orientato agli oggetti, il che significa che utilizza classi, che possono contenere dati ed eseguire codice, per progettare programmi. Le classi sono "prototipi" di oggetti, come l'idea di una mela è il prototipo della mela che si può effettivamente acquistare in un negozio. Si sa che una mela ha un colore, e che può essere sbucciata: questi sono i dati e il "codice" eseguibile per la classe mela.

Oxygene fornisce supporto a livello di linguaggio per alcune funzionalità della programmazione parallela. L'obiettivo è utilizzare tutti i core o processori di un computer per migliorare le prestazioni. Per raggiungere questo obiettivo, i compiti devono essere distribuiti su più thread. Il .NET Framework 's ThreadPoolclasse ha offerto un modo per in modo efficiente il lavoro con diversi thread. La Task Parallel Library (TPL) è stata introdotta in .NET 4.0 per fornire più funzionalità per la programmazione parallela.

Gli operatori possono essere sovraccaricati in Oxygene utilizzando la class operatorsintassi:

class operator implicit(i : Integer) : MyClass;

Si noti che per l'overload dell'operatore ogni operatore ha un nome, che deve essere utilizzato nella sintassi dell'overload dell'operatore, perché ad esempio "+" non sarebbe un nome di metodo valido in Oxygene.

Struttura del programma

Oxygene non usa "Unità" come fa Delphi, ma usa gli spazi dei nomi .NET per organizzare e raggruppare i tipi. Uno spazio dei nomi può estendersi su più file (e assembly), ma un file può contenere solo tipi di uno spazio dei nomi. Questo spazio dei nomi è definito nella parte superiore del file:

namespace ConsoleApplication1;

I file Oxygene sono separati in un'interfaccia e una sezione di implementazione, che è la struttura nota da Delphi. La sezione dell'interfaccia segue la dichiarazione dello spazio dei nomi. Contiene la usesclausola, che in Oxygene importa i tipi da altri namespace:

uses
  System.Linq;

Gli spazi dei nomi importati devono trovarsi nel progetto stesso o negli assembly a cui si fa riferimento. A differenza di C#, in Oxygene i nomi alias non possono essere definiti per gli spazi dei nomi, solo per i nomi di tipo singolo (vedi sotto).

Seguendo la usesclausola un file contiene dichiarazioni di tipo, come sono conosciute da Delphi:

interface

type
  ConsoleApp = class
  public
    class method Main;
  end;

Come in C#, il metodo Main è il punto di ingresso per ogni programma. Può avere un parametro args : Array of Stringper passare gli argomenti della riga di comando al programma.

È possibile dichiarare più tipi senza ripetere la typeparola chiave.

L'implementazione dei metodi dichiarati si trova nella sezione implementazione:

implementation

class method ConsoleApp.Main;
begin
  // add your own code here
  Console.WriteLine('Hello World.');
end;

end.

I file finiscono sempre con end.

tipi

Come linguaggio .NET, Oxygene utilizza il sistema di tipi .NET: esistono tipi di valore (come struct) e tipi di riferimento (come array o classi).

Sebbene non introduca tipi propri "predefiniti", Oxygene offre nomi generici più "pascalish" per alcuni di essi, in modo che ad esempio System.Int32possano essere utilizzati come Integere Boolean( System.Boolean), Char( System.Char), Real( System.Double) entrano a far parte della famiglia dei pascal- anche i nomi di tipo. Il carattere struct di questi tipi, che fa parte di .NET, è completamente conservato.

Come in tutti i linguaggi .NET i tipi in Oxygene hanno una visibilità. In Oxygene la visibilità predefinita è assembly, che è equivalente alla internalvisibilità in C#. L'altro tipo di visibilità possibile è public.

type
  MyClass = public class
end;

La visibilità può essere impostata per ogni tipo definito (classi, interfacce, record, ...).

È possibile definire un nome alias per i tipi, che può essere utilizzato localmente o in altri assembly Oxygene.

type
  IntList = public List<Integer>; //visible in other Oxygene-assemblies
  SecretEnumerable = IEnumerable<String>; //not visible in other assemblies

Gli alias di tipo pubblico non saranno visibili per altre lingue.

record

I record sono come vengono chiamate le strutture .NET in Oxygene. Sono dichiarati proprio come le classi, ma con la recordparola chiave:

type
  MyRecord = record
    method Foo;
  end;

Poiché sono solo strutture .NET, i record possono avere campi, metodi e proprietà, ma non hanno ereditarietà e non possono implementare interfacce .

Interfacce

Le interfacce sono un concetto molto importante nel mondo .NET, il framework stesso ne fa un uso massiccio. Le interfacce sono la specifica di un piccolo insieme di metodi, proprietà ed eventi che una classe deve implementare durante l'implementazione dell'interfaccia. Ad esempio, l'interfaccia IEnumerable<T>specifica il GetEnumeratormetodo utilizzato per scorrere le sequenze.

Le interfacce sono dichiarate proprio come le classi:

type
  MyInterface = public interface
    method MakeItSo : IEnumerable;
    property Bar : String read write;
  end;

Notare che per le proprietà il getter e il setter non sono specificati esplicitamente.

delegati

I delegati definiscono le firme per i metodi, in modo che questi metodi possano essere passati in parametri (ad esempio callback) o archiviati in variabili, ecc. Sono l'equivalente NET indipendente dai tipi ai puntatori a funzione. Sono utilizzati anche negli eventi. Quando si assegna un metodo a un delegato, si deve usare l' @operatore, quindi il compilatore sa che non si vuole chiamare il metodo ma semplicemente assegnarlo.

Oxygene può creare delegati anonimi; ad esempio i metodi possono essere passati al Invokemetodo di un controllo senza dichiarare il delegato:

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

DoSomethingVerrà creato dal compilatore un delegato anonimo con la firma del metodo .

Oxygene supporta delegati polimorfici, il che significa che i delegati che hanno parametri di tipi discendenti sono compatibili con l'assegnazione. Supponiamo due classi MyClasse MyClassEx = class(MyClass), quindi nel codice seguente l' BlubbExassegnazione è compatibile con Blubb.

type
  delegate Blubb(sender : Object; m : MyClass);
  delegate BlubbEx(sender : Object; mx : MyClassEx);

I campi possono essere utilizzati per delegare l'implementazione di un'interfaccia, se il tipo di cui sono implementa questa interfaccia:

Implementor = public class(IMyInterface)
  // ... implement interface ...
end;

MyClass = public class(IMyInterface)
  fSomeImplementor : Implementor; public implements IMyInterface; //takes care of implementing the interface
end;

In questo esempio il compilatore creerà metodi e proprietà pubblici in MyClass, che chiamano i metodi/proprietà di fSomeImplementor, per implementare i membri di IMyInterface. Questo può essere usato per fornire funzionalità di tipo mixin.

Metodi anonimi

I metodi anonimi sono implementati all'interno di altri metodi. Non sono accessibili all'esterno del metodo a meno che non vengano archiviati all'interno di un campo delegato. I metodi anonimi possono utilizzare le variabili locali del metodo in cui sono implementati e i campi della classe a cui appartengono.

I metodi anonimi sono particolarmente utili quando si lavora con codice che dovrebbe essere eseguito in un thread della GUI, cosa che viene eseguita in .NET passando un metodo do the Invokemethod ( Control.Invokein WinForms, Dispatcher.Invokein 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;

Anche i metodi anonimi possono avere parametri:

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;

Entrambi i codici sorgente utilizzano delegati anonimi .

Notifica di proprietà

La notifica della proprietà viene utilizzata principalmente per l'associazione dei dati, quando la GUI deve sapere quando cambia il valore di una proprietà. Il framework .NET fornisce le interfacce INotifyPropertyChangede INotifyPropertyChanging(in .NET 3.5) per questo scopo. Queste interfacce definiscono gli eventi che devono essere attivati ​​quando una proprietà viene modificata/è stata modificata.

L'ossigeno fornisce il notifymodificatore, che può essere utilizzato sulle proprietà. Se viene utilizzato questo modificatore, il compilatore aggiungerà le interfacce alla classe, le implementerà e creerà il codice per generare gli eventi quando la proprietà cambia/è stata modificata.

property Foo : String read fFoo write SetFoo; notify;
property Bar : String; notify 'Blubb'; //will notify that property "Blubb" was changed instead of "Bar"

Il modificatore può essere utilizzato su proprietà che hanno un metodo setter. Il codice per generare gli eventi verrà quindi aggiunto a questo metodo durante la fase di compilazione.

Esempi di codice

Ciao mondo

namespace HelloWorld;

interface

type
  HelloClass = class
  public
    class method Main;
  end;

implementation

class method HelloClass.Main;
begin
  System.Console.WriteLine('Hello World!');
end;

end.

Contenitore generico

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.

Metodo generico

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.

Uscita del programma:

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

Differenze tra Delphi e Oxygene

  • unit : sostituito con la parola chiave namespace . Poiché Oxygene non compila per file ma per progetto, non dipende dal nome del file. Invece la parola chiave unit o namespace viene utilizzata per denotare lo spazio dei nomi predefinito in cui sono definiti tutti i tipi per quel file
  • procedura e funzione : metodo è la parola chiave preferita, sebbene procedura e funzione funzionino ancora.
  • overload : in Oxygene tutti i metodi sono sovraccaricati per impostazione predefinita, quindi non è necessaria alcuna parola chiave speciale per questo
  • .Create() : questa chiamata al costruttore è stata sostituita dalla nuova parola chiave. Può ancora essere abilitato nelle opzioni del progetto per motivi legacy
  • string : i caratteri nelle stringhe sono in base zero e di sola lettura. Le stringhe possono avere valori nulli, quindi il test su stringhe vuote non è sempre sufficiente.

Critica

Alcune persone vorrebbero portare il loro codice Win32 Delphi su Oxygene senza apportare grandi modifiche. Questo non è possibile perché mentre Oxygene assomiglia a Delphi, ci sono abbastanza modifiche da renderlo incompatibile per una semplice ricompilazione. Sebbene il nome gli dia l'aspetto di un'altra versione di Delphi, ciò non è completamente vero.

Oltre alla differenza di lingua, il framework Visual Component Library non è disponibile in Oxygene. Ciò rende il porting ancora più difficile perché il classico codice Delphi si basa molto sulla VCL.

Guarda anche

Riferimenti

link esterno