Пожелания к синтаксису языка MQL

 

Решил создать такую тему, т.к. по моим наблюдениям, развитие синтаксиса MQL уже долгое время стоит на месте, за последние годы никаких улучшений в языке не видно.  Не знаю, собираются ли вообще разработчики работать над MQL дальше, но многих возможностей очень не хватает, некоторые из которых являются критически необходимыми.

В данной ветке я решил собрать в кучу основные пожелания.  Сначала приведу свой список, возможно кто-то дополнит ещё чем-нибудь.  А там по ходу дела может и разработчики подключатся и выскажут своё видение, было бы замечательно.

Данный список я расположил в порядке значимости (как я это вижу), но не в порядке моих личных приоритетов.  Т.е. сначала поставил наиболее фундаментальные и незаменимые вещи для языка. В качестве ориентира берём функционал языков C++ и C#


1. Работа с типами:  typedefdecltypeauto

Это в общем-то базовый функционал, по крайне мере два первых спецификатора.  Операции по именованию и взятию типов созданы не только для удобства, но и для надёжности и гибкости кода.  Если же везде жёстко закладываться на конкретные типы переменных, используемых в разных местах, то потом начинаются проблемы, когда понадобится поменять какой-либо из типов. 

С typedef многие тут уже знакомы, но к сожалению, это пока только обрубок, работающий лишь с указателями на функции.  По поводу decltype, кто не в курсе, поясню: он возвращает тип выражения, переданного ему в качестве аргумента, позволяя тем самым гибко задавать типы одних переменных или функций на основе типов других:

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

Либо с использованием typedef:

typedef int type;
type a= 100;
type b = a;
Либо например в случае длинных и сложных типов (например ClassA< ClassB< ClassC,ClassD<ClassE> > >) - тут сам бог велел оборачивать это в typedef

В С# вместо typedef используется using.

В MQL же ничего этого нет.  Единственное что можно - это костыльный вариант задания типа через define, который чреват проблемами.


2. Пространства имён:  namespace

Эту тему недавно уже обсуждали. Для меня вообще очень странно, почему оно до сих пор не реализовано, т.к. это обязательная вещь в языке. Особенно учитывая тренд на развитие комьюнити, использование кодобазы, групповой разработки. В этом случае проблема совпадающих имён становится очень актуальной.

Тут вон приводили пример, что даже когда имя локальной переменной внутри какой-то функции сопадает с названием типа, определённого в другом файле, то компилятор выдаёт ошибку. Безобразие.

Да и вообще это неправильно, когда всё свалено в одну кучу в едином пространстве.


3. Оператор приведения типа,  а точнее возможность его перегрузки в классе.  Без него пользовательские типы являются неполноценными по сути, гибкость сильно снижается.
Допустим, ты сделал структуру DATETIME, хранящую время, и хочешь чтобы её можно было также использовать в качестве datetime, передавая во все функции, принимающие datetime, равно как и используя в выражениях с datetime.
Обычно это делается просто: перегружаем конструктор и оператор кастинга соответствующим типом, и получаем полную совместимость нашей структуры с данным типом:

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

Но в MQL вместо этого приходится делать отдельный метод  to_datetime() и везде прописывать его вызов. Либо же перегружать целевые функции для типа DATETIME &, что тоже не добавляет комфорта и гибкости.


4. Множественные интерфейсы.  Ну об этом уже много было слухов и разговоров (помню ещё года три назад писали в сервис-деске, что идёт работа), но что-то подзатянулся процесс... Если он вообще идёт.



5. Поддержка интерфейсов для структур.  Это необходимо для унифицированной работы с ООП.  Сейчас зачастую приходится городить костыли.

Данный функционал можно реализовать двумя способами:  либо как в C# - через запаковку/распаковку (boxing) ,  либо более гибкий вариант - путём создания динамического дескриптора для структуры, привязанного к дескриптору динамического объекта, в составе которого расположена структура - так было бы эффективней, плюс фактически появилась бы возможность создания указателей на структуры и другие типы данных, что существенно повысило бы гибкость.


6. Возможность передачи структур по значению,  что актуально при передачи маленьких структур (тот же DATETIME из примера выше), что позволит гибкие преобразования на лету из одного типа в другой, если конструктор структуры поддерживает такой тип. При передаче по ссылке такой гибкости нет.  Хотя если будут реализованы интерфейсы для структур, то это станет менее актуально.


7. Возможность задания числовых параметров шаблона:

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);
}

Что касается второго примера, то в MQL4 можно обойтись и без этого, т.к. там функции принимают массивы любых размерностей. А вот в MQL5 всё гораздо сложнее с многомерными массивами.


8. Специализация шаблонов (раздельная реализация для конкретных типов).

Пример с функцией:
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>()); }

Пример с классом:
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();
}



Ну и так по мелочи:


9. Возможность приведения (явного или неявного) массива указателей к массиву базовых указателей.   В старых билдах это работало, и было очень удобно:

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

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

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

Сейчас же приходится перекопировать массив в новый массив, а потом обратно, напрасные расходы.
 

10.  Приведение ссылки на объект:   (type&)object

Это необходимо для возможности передачи приведённых объектов в функцию. В следующем примере требуется записать в файл объект класса B как объект базового класса A, однако сейчас это сделать невозможно, требуется создавать промежуточную функцию либо перекопировать объект в новый объект.   

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. Инициализации массивов и структур не только константами, а любыми выражениями.  Это значительно сокращает и упрощает код в таких случаях:

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


12. Возможность явного приведения указателя к числовому значению. 

Это позволит сортировать массивы указателей по их значениям с целью быстрого поиска нужного указателя через бинарный поиск, либо через создание хэш таблицы.  Сейчас возможно получение числового значения только посредством преобразования в текстовый вид, что убивает всю затею.

13. Задание шаблонных параметров по умолчанию

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;
 

На мой взгляд, все это нужно очень небольшому числу народа.

Судя по коду в Кодобазе - 95% пользователей ООП используют крайне слабо. А из оставшихся 5% большей части - все эти возможности малоупотребительны. Безусловно, они приятны, и даже могут быть полезны, но большой надобности во всех этих улучшениях, по-моему, нет.

 
Georgiy Merts:

На мой взгляд, все это нужно очень небольшому числу народа.

Судя по коду в Кодобазе - 95% пользователей ООП используют крайне слабо. А из оставшихся 5% большей части - все эти возможности малоупотребительны. Безусловно, они приятны, и даже могут быть полезны, но большой надобности во всех этих улучшениях, по-моему, нет.

Да, я понимаю, но помимо кодобазы есть ещё Фриланс и Маркет, и вот там MQ должно быть заинтересованы в качестве продуктов.  А качество языка так или иначе влияет на качество и скорость разработки и отладки.

А если так рассуждать насчёт процентов, тогда зачем вообще был создан MQL5?  Сидели бы до сих пор на старом хардкорном MQL4, где не нужно ни ООП, ни всё прочее... 99% пользователей всё устраивало )   

Возможно нормальные программисты и не идут на MQL именно потому, что это пока неполноценный язык.

 
Alexey Navoykov:

Решил создать такую тему, т.к. по моим наблюдениям, развитие синтаксиса MQL уже долгое время стоит на месте, за последние годы никаких улучшений в языке не видно.  Не знаю, собираются ли вообще разработчики работать над MQL дальше, но многих возможностей очень не хватает, некоторые из которых являются критически необходимыми.

В данной ветке я решил собрать в кучу основные пожелания.  Сначала приведу свой список, возможно кто-то дополнит ещё чем-нибудь.  А там по ходу дела может и разработчики подключатся и выскажут своё видение, было бы замечательно.

Данный список я расположил в порядке значимости (как я это вижу), но не в порядке моих личных приоритетов.  Т.е. сначала поставил наиболее фундаментальные и незаменимые вещи для языка. В качестве ориентира берём функционал языков C++ и C#


1. Работа с типами:  typedefdecltypeauto

Это в общем-то базовый функционал, по крайне мере два первых спецификатора.  Операции по именованию и взятию типов созданы не только для удобства, но и для надёжности и гибкости кода.  Если же везде жёстко закладываться на конкретные типы переменных, используемых в разных местах, то потом начинаются проблемы, когда понадобится поменять какой-либо из типов. 

С typedef многие тут уже знакомы, но к сожалению, это пока только обрубок, работающий лишь с указателями на функции.  По поводу decltype, кто не в курсе, поясню: он возвращает тип выражения, переданного ему в качестве аргумента, позволяя тем самым гибко задавать типы одних переменных или функций на основе типов других:

Либо с использованием typedef:

Либо например в случае длинных и сложных типов (например ClassA< ClassB< ClassC,ClassD<ClassE> > >) - тут сам бог велел оборачивать это в typedef

В С# вместо typedef используется using.

В MQL же ничего этого нет.  Единственное что можно - это костыльный вариант задания типа через define, который чреват проблемами.


2. Пространства имён:  namespace

Эту тему недавно уже обсуждали. Для меня вообще очень странно, почему оно до сих пор не реализовано, т.к. это обязательная вещь в языке. Особенно учитывая тренд на развитие комьюнити, использование кодобазы, групповой разработки. В этом случае проблема совпадающих имён становится очень актуальной.

Тут вон приводили пример, что даже когда имя локальной переменной внутри какой-то функции сопадает с названием типа, определённого в другом файле, то компилятор выдаёт ошибку. Безобразие.

Да и вообще это неправильно, когда всё свалено в одну кучу в едином пространстве.


3. Оператор приведения типа,  а точнее возможность его перегрузки в классе.  Без него пользовательские типы являются неполноценными по сути, гибкость сильно снижается.
Допустим, ты сделал структуру DATETIME, хранящую время, и хочешь чтобы её можно было также использовать в качестве datetime, передавая во все функции, принимающие datetime, равно как и используя в выражениях с datetime.
Обычно это делается просто: перегружаем конструктор и оператор кастинга соответствующим типом, и получаем полную совместимость нашей структуры с данным типом:

Но в MQL вместо этого приходится делать отдельный метод  to_datetime() и везде прописывать его вызов. Либо же перегружать целевые функции для типа DATETIME &, что тоже не добавляет комфорта и гибкости.


4. Множественные интерфейсы.  Ну об этом уже много было слухов и разговоров (помню ещё года три назад писали в сервис-деске, что идёт работа), но что-то подзатянулся процесс... Если он вообще идёт.



5. Поддержка интерфейсов для структур.  Это необходимо для унифицированной работы с ООП.  Сейчас зачастую приходится городить костыли.

Данный функционал можно реализовать двумя способами:  либо как в C# - через запаковку/распаковку (boxing) ,  либо более гибкий вариант - путём создания динамического дескриптора для структуры, привязанного к дескриптору динамического объекта, в составе которого расположена структура - так было бы эффективней, плюс фактически появилась бы возможность создания указателей на структуры и другие типы данных, что существенно повысило бы гибкость.


6. Возможность передачи структур по значению,  что актуально при передачи маленьких структур (тот же DATETIME из примера выше), что позволит гибкие преобразования на лету из одного типа в другой, если конструктор структуры поддерживает такой тип. При передаче по ссылке такой гибкости нет.  Хотя если будут реализованы интерфейсы для структур, то это станет менее актуально.


7. Возможность задания числовых параметров шаблона:

Что касается второго примера, то в MQL4 можно обойтись и без этого, т.к. там функции принимают массивы любых размерностей. А вот в MQL5 всё гораздо сложнее с многомерными массивами.


8. Специализация шаблонов (раздельная реализация для конкретных типов).

Пример с функцией:

Пример с классом:



Ну и так по мелочи:


9. Возможность приведения (явного или неявного) массива указателей к массиву базовых указателей.   В старых билдах это работало, и было очень удобно:

Сейчас же приходится перекопировать массив в новый массив, а потом обратно, напрасные расходы.
 

10.  Приведение ссылки на объект:   (type&)object

Это необходимо для возможности передачи приведённых объектов в функцию. В следующем примере требуется записать в файл объект класса B как объект базового класса A, однако сейчас это сделать невозможно, требуется создавать промежуточную функцию либо перекопировать объект в новый объект.   


11. Инициализации массивов и структур не только константами, а любыми выражениями.  Это значительно сокращает и упрощает код в таких случаях:


12. Возможность явного приведения указателя к числовому значению. 

Это позволит сортировать массивы указателей по их значениям с целью быстрого поиска нужного указателя через бинарный поиск, либо через создание хэш таблицы.  Сейчас возможно получение числового значения только посредством преобразования в текстовый вид, что убивает всю затею.

13. Задание шаблонных параметров по умолчанию

Поддерживаю.

 
Georgiy Merts:

На мой взгляд, все это нужно очень небольшому числу народа.

Судя по коду в Кодобазе - 95% пользователей ООП используют крайне слабо. А из оставшихся 5% большей части - все эти возможности малоупотребительны. Безусловно, они приятны, и даже могут быть полезны, но большой надобности во всех этих улучшениях, по-моему, нет.

Это небольшое число народа может написать библиотеки, которые будут использовать все.

 

14. Разрешить передавать временный объект, если аргумент функции константная ссылка.

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. Ключевое слово friend.

Для некоторых классов, хочется дать доступ к закрытым членам, какому-то конкретному классу, но не всем.

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. Обнулять переменную при явном вызове конструктора для встроенных типов

Это пригодится в шаблонах.

   double x;         // Не инициализирована
   double y();       // Инициализирована нулём
   double z = 5.0;   // Инициализирована 5.0
 
У них даже указателей нет) что уж может быть фундаментальнее)
 
Alexey Navoykov:

Решил создать такую тему, т.к. по моим наблюдениям, развитие синтаксиса MQL уже долгое время стоит на месте, за последние годы никаких улучшений в языке не видно.  Не знаю, собираются ли вообще разработчики работать над MQL дальше, но многих возможностей очень не хватает, некоторые из которых являются критически необходимыми.

В данной ветке я решил собрать в кучу основные пожелания.  Сначала приведу свой список, возможно кто-то дополнит ещё чем-нибудь.  А там по ходу дела может и разработчики подключатся и выскажут своё видение, было бы замечательно.

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

Жди бана, критика священного писания недопустима :)

PS: Улучшения были, не такие глобальные, но были

 
secret:
У них даже указателей нет) что уж может быть фундаментальнее)

Их не будет, язык управляемый, хоть и без GC

В шарпе тоже они есть только в небезопасном режиме.

 
Alexey Navoykov:

Да, я понимаю, но помимо кодобазы есть ещё Фриланс и Маркет, и вот там MQ должно быть заинтересованы в качестве продуктов.  А качество языка так или иначе влияет на качество и скорость разработки и отладки.

А если так рассуждать насчёт процентов, тогда зачем вообще был создан MQL5?  Сидели бы до сих пор на старом хардкорном MQL4, где не нужно ни ООП, ни всё прочее... 99% пользователей всё устраивало )   

Возможно нормальные программисты и не идут на MQL именно потому, что это пока неполноценный язык.

Кодобаза вообще помойка на 95%. Что-то давно новых версий МТ5 не выходило. Ренат, помнится, обещал что-то глобальное в новом релизе.

 
Alexey Volchanskiy:

PS: Улучшения были, не такие глобальные, но были

Ну а что именно было?  Последнее что помню, был неявный оператор копирования, позволяющий копировать динамические объекты, но это мелочь, тем более что с тех пор уже куча времени прошло.