Suggerimenti per la sintassi MQL

 

Ho deciso di creare un tale argomento, perché secondo le mie osservazioni, lo sviluppo della sintassi MQL è stato stagnante per molto tempo, non riesco a vedere alcun miglioramento del linguaggio negli ultimi anni. Non so se gli sviluppatori hanno intenzione di lavorare su MQL, ma molte delle caratteristiche sono molto mancanti, alcune delle quali sono criticamente necessarie.

In questo thread ho deciso di compilare una lista delle mie richieste principali. Darò prima la mia lista, forse qualcuno aggiungerà qualcos'altro, e poi forse gli sviluppatori si uniranno e condivideranno la loro visione, sarebbe bello.

Questa lista l'ho messa in ordine d'importanza (come la vedo io), ma non in ordine di priorità personali, cioè prima metto le cose più fondamentali e indispensabili per la lingua. Prendete le funzionalità di C++ e C# come punto di riferimento


1. Lavorare con i tipi: typedef, decltype, auto

Questa è in realtà una funzionalità di base, almeno i primi due specificatori. Le operazioni di naming e type hopping sono create non solo per la comodità, ma anche per l'affidabilità e la flessibilità del codice. Se si imposta un valore fisso su tipi concreti di variabili usate in luoghi diversi, si avranno problemi quando si avrà bisogno di cambiare uno qualsiasi dei tipi.

Molti di voi hanno già familiarità con typedef, ma purtroppo è ancora un ceppo che funziona solo con i puntatori di funzione. Per coloro che non hanno familiarità con decltype, lasciatemi chiarire: restituisce il tipo dell'espressione passatagli come argomento, permettendo la flessibilità di definire i tipi di certe variabili o funzioni sulla base dei tipi di altre:

int a=100;
//...
decltype(a) b= a;

O usando typedef:

typedef int type;
type a= 100;
type b = a;
O per esempio nel caso di tipi lunghi e complessi (per esempio ClassA< ClassB< ClassC,ClassD<ClassE> >) - qui è una manna dal cielo avvolgerlo in typedef

In C#, si usa using invece di typedef.

L'unica cosa possibile è la variante crostosa della definizione dei tipi tramite define che è piena di problemi.


2. Spazi dei nomi: namespace

Questo argomento è già stato discusso recentemente. Per me è davvero strano che non sia stato ancora implementato, perché è una caratteristica indispensabile del linguaggio. Soprattutto considerando la tendenza verso la comunità, il codobase e lo sviluppo di gruppo. In questo caso, il problema della corrispondenza dei nomi diventa molto rilevante.

Hanno citato un esempio che anche quando il nome di una variabile locale all'interno di qualche funzione è identico al nome di un tipo definito in un altro file, il compilatore genera un errore. È un oltraggio.

In generale, è sbagliato avere tutto in una pila in uno spazio.


Senza di esso, i tipidefiniti dall'utente sono intrinsecamente incompleti e la flessibilità è notevolmente ridotta.
Supponiamo che abbiate creato una struttura DATETIME che memorizza l'ora, e volete essere in grado di usarla come datetime, passandola a tutte le funzioni che accettano datetime, così come usarla nelle espressioni con datetime.
Di solito questo si fa semplicemente: si sovraccarica il costruttore e la dichiarazione di cast con il tipo corrispondente, e si ottiene la piena compatibilità della nostra struttura con questo tipo:

struct DATETIME
{
  DATETIME(datetime time) { ... }
  operator datetime() const { return ...; }
};

Ma in MQL invece è necessario creare un metodo separato to_datetime() e scrivere la sua chiamata ovunque. Oppure la chiamata della funzione di destinazione DATETIME & type deve essere sovraccaricata, il che non aumenta la comodità e la flessibilità.


4. Interfacce multiple... Beh, ci sono già state molte voci e discorsi a riguardo (ricordo che tre anni fa scrissero nel service-desk che il lavoro è in corso), ma la cosa si trascina... Se è in corso.



5. Ilsupporto di interfacce per le strutture è necessario per un lavoro unificato con OOP. Attualmente, dobbiamo spesso fare delle stampelle.

Questa funzionalità potrebbe essere implementata in due modi: o come in C# - via packaging/unpacking (boxing), o in modo più flessibile - creando un handle dinamico per la struttura collegato a un descrittore di oggetto dinamico che contiene la struttura - sarebbe più efficiente, in più si potrebbero creare puntatori a strutture e altri tipi di dati, il che aumenterebbe la flessibilità.


6. Possibilità di passare le strutture per valore, il che è importante quando si passano le strutture piccole (DATETIME dell'esempio precedente), che permetterebbe conversioni flessibili al volo da un tipo all'altro, se il costruttore della struttura supporta questo tipo. Quando si trasferisce per riferimento, non c'è questa flessibilità. Anche se se le interfacce per le strutture sono implementate, diventerà meno rilevante.


7. Possibilità di specificare i parametri numerici del modello:

template<int N>
struct A
{
  char a[N];
};

A<100> a;
template<int N>
void f(int &arr[][N]) {  }

void start()
{
  int a[][5];
  f(a);
}

Per quanto riguarda il secondo esempio, in MQL4 se ne può fare a meno, perché lì le funzioni accettano array di qualsiasi dimensione. E in MQL5, tutto è molto più complicato con gli array multidimensionali.


8. Specializzazione dei modelli (implementazione separata per tipi specifici).

Esempio di funzione:
struct A
{
  double _value;
 
  template<typename T>
   T      ToType() { return (T)round(_value); }  
  template<>
   double ToType() { return _value; }
  template<>
   float  ToType() { return (float)_value; }
  template<>
   string ToType() { return DoubleToString(_value, 2); }
};

void f(A& a) { Print(a.ToType<string>()); }

Esempio con una classe:
template<typename T>
struct CArrayBase    // Базовый класс массива
{
  T _data[];
  int Size()          { return ArraySize(_data); }
  T operator[](int i) { return _data[i]; }
};

template<typename T>
struct CArray : CArrayBase<T> { };  // Основной класс массива

template<>
struct CArray<double> : CArrayBase<double>  // Специализация класса для массива double
{
  double Sum() { double sum=0;  for (int i=0; i<Size(); i++) sum+=_data[i];  return sum; } 
}; 

template<typename T>
struct CArray<T*> : CArrayBase<T*>  // Специализация класса для массива указателей
{
  void DeleteObjects() { for (int i=0; i<Size(); i++) { delete _data[i]; _data[i]=NULL; } }    
};

void start()
{
  CArray<double> arr1;
  arr1.Sum();  

  class A { };
  
  CArray<A*> arr2;
  arr2.DeleteObjects();
}



E così via:


9. La possibilità di fondere (esplicitamente o implicitamente) un array di puntatori in un array di puntatori di base. Nelle vecchie costruzioni questo funzionava, ed era molto comodo:

interface I { };
class A : I { };

void f(I* &Array[]) {  }

void Main(A* &array[]) { f(array); }

Ora dobbiamo ricopiare l'array in uno nuovo, e poi di nuovo indietro, fatica sprecata.

10. casting di riferimento all'oggetto:(tipo&)oggetto

Questo è necessario per poter passare un oggetto referenziato a una funzione. L'esempio seguente richiede che un oggetto della classe B sia scritto in un file come un oggetto della classe base A, ma questo non può essere fatto ora, deve essere creata una funzione intermedia o l'oggetto deve essere copiato in un nuovo oggetto.

struct A { int a; };

struct B : A { int b; };

B b;

void main()
{
  int h= FileOpen("MyFile",FILE_BIN|FILE_WRITE);
  FileWriteStruct(h, (A&)b);  // '&' - unexpected token
  FileClose(h); 
}


11. inizializzare array e strutture non solo con costanti, ma con qualsiasi espressione. Questo riduce e semplifica significativamente il codice in questi casi:

void f(int a, int b, int c, int d, int e, int f)
{
  int arr[]= { a, b, c, d, e, f };
 //......
}


12. Possibilità di lanciare esplicitamente un puntatore a un valore numerico.

Permetterebbe di ordinare gli array di puntatori in base ai loro valori per trovare rapidamente il puntatore necessario attraverso una ricerca binaria o creando una tabella hash. Ora è possibile ottenere un valore numerico solo attraverso la conversione in modalità testo, il che uccide l'intera idea.

13. Impostazione dei parametri predefiniti del modello

template<typename T>
struct DefaultConstructor { static T* New() { return new T; } };

template<typename T, typename TConstructor=DefaultConstructor<T>>
struct A
{
  T* data;
  A() { data= TConstructor::New(); }
 ~A() { delete data; }
};

class B { };

A<B> a;
 

A mio parere, poche persone hanno bisogno di tutto questo.

A giudicare dal codice in Kodobase - il 95% degli utenti usa OOP molto poco. E del restante 5% della maggioranza - tutte queste caratteristiche sono poco usate. Certamente, sono piacevoli e possono anche essere utili, ma non c'è una grande necessità in tutti questi miglioramenti, secondo me.

 
Georgiy Merts:

A mio parere, poche persone hanno bisogno di tutto questo.

A giudicare dal codice in Kodobase - il 95% degli utenti usa OOP molto male. E del restante 5% la maggior parte di loro non usa molto queste funzioni. Certo, sono piacevoli e possono anche essere utili, ma non c'è un gran bisogno di tutti questi miglioramenti secondo me.

Sì, capisco, ma oltre a kodobase ci sono Freelance e Market, e lì MQ deve essere interessato alla qualità dei prodotti. E la qualità del linguaggio influenza la qualità e la velocità di sviluppo e debug in un modo o nell'altro.

Se si parla di percentuali come questa, allora perché è stato creato MQL5? Saremmo ancora seduti nel vecchio e duro MQL4 dove OOP o qualsiasi altra cosa non è richiesta... Il 99% degli utenti ne sono stati contenti)

Forse i programmatori normali non stanno andando in MQL proprio perché è ancora un linguaggio incompleto.

 
Alexey Navoykov:

Ho deciso di creare un tale argomento, in quanto secondo le mie osservazioni, lo sviluppo della sintassi MQL è stato stagnante per molto tempo, nessun miglioramento nel linguaggio negli ultimi anni. Non so se gli sviluppatori hanno intenzione di lavorare ulteriormente su MQL, ma molte caratteristiche sono molto mancanti, alcune delle quali sono criticamente necessarie.

In questo thread ho deciso di compilare una lista delle mie richieste principali. Darò prima la mia lista, forse qualcuno aggiungerà qualcos'altro, e poi forse gli sviluppatori si uniranno e condivideranno la loro visione, sarebbe bello.

Questa lista l'ho messa in ordine d'importanza (come la vedo io), ma non in ordine di priorità personali, cioè prima metto le cose più fondamentali e indispensabili per la lingua. Prendete le funzionalità di C++ e C# come punto di riferimento


1. Lavorare con i tipi: typedef, decltype, auto

Questa è in realtà una funzionalità di base, almeno i primi due specificatori. Le operazioni di naming e type hopping sono create non solo per la comodità, ma anche per l'affidabilità e la flessibilità del codice. Se si imposta un valore fisso su tipi concreti di variabili utilizzate in luoghi diversi, si avranno problemi quando si avrà bisogno di cambiare uno qualsiasi dei tipi.

Molti di voi qui hanno già familiarità con typedef, ma purtroppo è ancora un moncherino che funziona solo con i puntatori di funzione. Per quanto riguarda decltype, permettetemi di chiarire per coloro che non hanno familiarità con esso: restituisce il tipo di espressione passatogli come argomento, permettendo la flessibilità di definire tipi di variabili o funzioni basate su altri tipi:

O usando typedef:

O per esempio nel caso di tipi lunghi e complessi (per esempio ClassA< ClassB< ClassC,ClassD<ClassE> >) - qui è una manna dal cielo avvolgerlo in typedef

In C#, si usa using invece di typedef.

L'unica cosa possibile è la variante crostosa della definizione dei tipi tramite define che è piena di problemi.


2. Spazi dei nomi: namespace

Questo argomento è già stato discusso recentemente. Per me è davvero strano che non sia stato ancora implementato, perché è una caratteristica indispensabile del linguaggio. Soprattutto considerando la tendenza verso la comunità, il codobase e lo sviluppo di gruppo. In questo caso, il problema della corrispondenza dei nomi diventa molto rilevante.

Hanno citato un esempio che anche quando il nome di una variabile locale all'interno di qualche funzione è identico al nome di un tipo definito in un altro file, il compilatore genera un errore. È un oltraggio.

Inoltre, è sbagliato avere tutto in un posto in una pila.


Senza di esso, i tipidefiniti dall'utente sono intrinsecamente incompleti e la flessibilità è notevolmente ridotta.
Supponiamo che abbiate creato una struttura DATETIME che memorizza l'ora, e volete essere in grado di usarla come datetime, passandola a tutte le funzioni che accettano datetime, così come usarla nelle espressioni con datetime.
Di solito questo si fa semplicemente: si sovraccarica il costruttore e la dichiarazione di cast con il tipo corrispondente, e si ottiene la piena compatibilità della nostra struttura con questo tipo:

Ma in MQL invece è necessario creare un metodo separato to_datetime() e scrivere la sua chiamata ovunque. Oppure la chiamata della funzione di destinazione DATETIME & type deve essere sovraccaricata, il che non aumenta la comodità e la flessibilità.


4. Interfacce multiple... Beh, ci sono già state molte voci e discorsi a riguardo (ricordo che tre anni fa scrissero nel service-desk che il lavoro è in corso), ma la cosa si trascina... Se è in corso.



5. Ilsupporto di interfacce per le strutture è necessario per un lavoro unificato con OOP. Attualmente, dobbiamo spesso fare delle stampelle.

Questa funzionalità potrebbe essere implementata in due modi: o come in C# - via packaging/unpacking (boxing), o in modo più flessibile - creando un handle dinamico per la struttura collegato a un descrittore di oggetto dinamico che contiene la struttura - sarebbe più efficiente, in più si potrebbero creare puntatori a strutture e altri tipi di dati, il che aumenterebbe la flessibilità.


6. Possibilità di passare le strutture per valore, il che è importante quando si passano le strutture piccole (DATETIME dell'esempio precedente), che permetterebbe conversioni flessibili al volo da un tipo all'altro, se il costruttore della struttura supporta questo tipo. Non c'è tale flessibilità quando si trasferisce per riferimento, anche se se le interfacce per le strutture sono implementate, diventerà meno rilevante.


7. Possibilità di specificare i parametri numerici del modello:

Per quanto riguarda il secondo esempio, in MQL4 se ne può fare a meno, perché lì le funzioni accettano array di qualsiasi dimensione. E in MQL5, tutto è molto più complicato con gli array multidimensionali.


8. Specializzazione dei modelli (implementazione separata per tipi specifici).

Esempio di funzione:

Esempio con una classe:



E così per le piccole cose:


9. La possibilità di fondere (esplicitamente o implicitamente) un array di puntatori in un array di puntatori di base. Nelle vecchie costruzioni questo funzionava, ed era molto comodo:

Ora dobbiamo ricopiare l'array in uno nuovo, e poi di nuovo indietro, fatica sprecata.

10. casting di riferimento all'oggetto:(tipo&)oggetto

Questo è necessario per poter passare un oggetto referenziato a una funzione. L'esempio seguente richiede che un oggetto della classe B sia scritto in un file come un oggetto della classe base A, ma questo non può essere fatto ora, deve essere creata una funzione intermedia o l'oggetto deve essere copiato in un nuovo oggetto.


11. inizializzare array e strutture non solo con costanti, ma con qualsiasi espressione. Questo riduce e semplifica significativamente il codice in questi casi:


12. Possibilità di lanciare esplicitamente un puntatore a un valore numerico.

Permetterebbe di ordinare gli array di puntatori in base ai loro valori per trovare rapidamente il puntatore necessario attraverso una ricerca binaria o creando una tabella hash. Ora è possibile ottenere un valore numerico solo attraverso la conversione in una forma testuale, il che uccide l'intera idea.

13. Impostazione dei parametri predefiniti del modello

Io sostengo.

 
Georgiy Merts:

Secondo me, un numero molto piccolo di persone ha bisogno di tutto questo.

A giudicare dal codice in Kodobase - il 95% degli utenti usa OOP molto poco. E del restante 5% della maggior parte - tutte queste caratteristiche sono poco usate. Certo, sono belli e possono anche essere utili, ma non c'è un gran bisogno di tutti questi miglioramenti, secondo me.

Questo piccolo numero di persone può scrivere librerie che tutti useranno.

 

14. Permette di passare un oggetto temporaneo se l'argomento della funzione è un riferimento costante.

template< typename Type >
struct complex
{
   Type Re;
   Type Im;
   
   complex() : Re(), Im(){}
   complex( Type re, Type im ) : Re(re), Im(im){}
};

template< typename Type >
void Func( const Type& val )
{
}

void OnStart()
{
   Func( 5.0 );
   
   complex< double > C( 1.0, 5.0 );
   Func( C );
   
   Func( complex< double >( 2.0, 4.0 ) );
}

15. la parola chiave amico.

Per alcune classi, volete dare accesso ai membri privati, ad una classe particolare, ma non a tutti.

template< typename Type >
class Matrix;

template< typename Type >
class MatrixData
{
   friend class Matrix< Type >;
   
   int mRefCount;
   int mRows;
   int mColumns;
   
   Type mArray[];
   
public:
   MatrixData();
   MatrixData( int rows, int cols );
};

template< typename Type >
class matrix
{
   MatrixData< Type >* mData;
   
public:
        Matrix();
        Matrix( int rows, int cols );
};

16. annullare una variabile quando si chiama esplicitamente il costruttore per i tipi incorporati

Questo è utile nei modelli.

   double x;         // Не инициализирована
   double y();       // Инициализирована нулём
   double z = 5.0;   // Инициализирована 5.0
 
Non hanno nemmeno la segnaletica) cosa c'è di più fondamentale)
 
Alexey Navoykov:

Ho deciso di creare un tale argomento, perché secondo la mia osservazione lo sviluppo della sintassi MQL è stato stagnante per molto tempo, nessun miglioramento nel linguaggio è stato fatto durante gli ultimi anni. Non so se gli sviluppatori hanno intenzione di lavorare su MQL a tutti, ma molte caratteristiche sono davvero mancanti, alcune di esse sono criticamente necessarie.

In questo thread ho deciso di compilare i principali desideri, prima darò la mia lista, forse qualcuno aggiungerà qualcos'altro. E poi forse gli sviluppatori si collegheranno ed esprimeranno la loro visione, sarebbe fantastico.

************

Aspettatevi un ban, le critiche alle scritture non sono permesse :)

PS: I miglioramenti sono stati, non così globale, ma ci sono stati

 
secret:
Non hanno nemmeno i puntatori) cosa c'è di più fondamentale)

Non ce ne saranno, la lingua è gestita, anche se senza GC

Anche Sharp li ha solo in modalità non sicura.

 
Alexey Navoykov:

Sì, capisco, ma oltre a kodobase ci sono Freelance e Market, e lì MQ deve essere interessato alla qualità dei prodotti. E la qualità del linguaggio influenza la qualità e la velocità di sviluppo e debugging in un modo o nell'altro.

Se si parla di percentuali come questa, allora perché è stato creato MQL5 in primo luogo? Saremmo ancora seduti nel vecchio MQL4 hardcore dove OOP o qualsiasi altra cosa non è richiesta... Il 99% degli utenti ne sono stati contenti)

Forse i programmatori normali non stanno andando in MQL perché è ancora un linguaggio incompleto.

Kodobase è al 95% spazzatura. Non vedo nuove versioni di MT5 da molto tempo. Renat, ricordo, ha promesso qualcosa di globale nella nuova release.

 
Alexey Volchanskiy:

PS: Ci sono stati miglioramenti, non così globali, ma ci sono stati

L'ultima cosa che ricordo era un operatore di copia implicita che permetteva di copiare oggetti dinamici, ma non è niente, soprattutto perché è passato molto tempo da allora.