对MQL语法的建议

Alexey Navoykov  

我决定创建这样一个话题,因为根据我的观察,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来包装它是一个天大的好消息。

在C#中,使用using 来代替typedef。

唯一可能的是通过定义 类型定义的硬壳变体,它充满了一些问题。


2.命名空间:命名空间

这个话题最近已经讨论过了。对我来说,这真的很奇怪,为什么它还没有被实现,因为它是该语言的一个必须的功能。特别是考虑到社区、代码库和团体发展的趋势。在这种情况下,名称匹配的问题变得非常重要。

他们举了一个例子,即使某个函数里面的局部变量的名称 与另一个文件中定义的类型的名称 相同,编译器也会产生一个错误。这是一种愤怒的行为。

一般来说,在一个空间里把所有东西都堆在一起是不对的。


没有它,用户定义的 类型本质上是不完整的,灵活性大大降低。
假设你已经创建了一个存储时间的结构DATETIME,你希望能够把它作为数据时间使用,把它传递给所有接受数据时间的函数,以及在带有数据时间的表达式中使用它。
通常情况下,这样做很简单:用相应的类型重载构造函数和铸造语句,你就可以得到我们的结构与这个类型的完全兼容。

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

但在MQL中,有必要创建一个单独的to_datetime() 方法,并将其调用写入各处。或者对DATETIME & type的目标函数的调用必须是重载的,这也不能增加舒适性和灵活性。


4.多接口......嗯,已经有很多关于它的传言和讨论了(我记得三年前他们在服务台写道,工作正在进行中),但它被拖了下来......如果它是在进行的话。



5.支持结构的接口 对于OOP的统一工作是必要的。 目前,我们常常不得不做拐杖。

这个功能可以通过两种方式实现:要么像C#那样--通过打包/解包(装箱),要么以更灵活的方式--为结构创建一个动态句柄,链接到包含该结构的动态对象的描述符--这样会更有效率,另外你可以创建指向结构和其他数据类型的指针,这将增加灵活性。


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.对象引用铸造:(类型&)对象

这是必要的,以便能够将一个被引用的对象传递给一个函数。下面的例子要求将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;
Georgiy Merts  

在我看来,很少有人需要这一切。

从Kodobase的代码来看 - 95%的用户很少使用OOP。而在剩下的5%的大多数人中--所有这些功能都很少使用。当然,它们是令人愉快的,甚至可以是有用的,但在我看来,所有这些改进并没有很大的必要性。

Alexey Navoykov  
Georgiy Merts:

在我看来,很少有人需要这一切。

从Kodobase的代码来看--95%的用户对OOP的使用非常糟糕。而剩下的5%的人中,大多数人不怎么使用这些功能。当然,它们是令人愉快的,甚至可以是有用的,但在我看来,所有这些改进并没有很大的必要性。

是的,我明白,但除了kodobase,还有Freelance和Market,那里的MQ一定对产品的质量感兴趣。 而语言的质量会以某种方式影响开发和调试的质量和速度。

如果像这样谈论百分比,那么为什么一开始就创建了MQL5? 我们仍然会坐在老式的硬核MQL4中,OOP或其他任何东西都不需要。99%的用户对其表示满意 )

也许正常的程序员不会去MQL,正是因为它仍然是一种不完整的语言。

Koldun Zloy  
Alexey Navoykov:

我决定创建这样一个主题,因为根据我的观察,MQL语法的发展已经停滞了很长时间,在过去几年里,语言没有任何改进。 我不知道开发人员是否会进一步研究MQL,但许多功能非常缺失,其中一些是急需的。

在这个主题中,我决定把我的主要要求汇编成一个清单。 我先给出我的清单,也许有人会补充一些别的东西,然后也许开发者会加入进来,表达他们的观点,那就更好了。

这份清单我是按照重要性的顺序排列的(在我看来),但不是按照我个人的优先次序排列的。 也就是说,首先把最基本的、对语言来说不可缺少的东西放在一起。以C++和C#的功能为基准


1.与类型一起工作:typedefdecltypeauto

这实际上是一个基本的功能,至少是前两个指定器。 命名和类型跳转操作的产生不仅是为了方便,也是为了代码的可靠性和灵活性。 如果你对不同地方使用的具体类型的变量设置一个固定的值,当你需要改变任何一个类型时,你会遇到问题。

在座的很多人已经熟悉了typedef,但不幸的是,它仍然是一个只适用于函数指针的树桩。 至于decltype,让我为那些不熟悉它的人澄清一下:它返回作为参数传递给它的表达式的类型,允许根据其他类型来灵活定义变量或函数的类型。

要么使用typedef。

或者例如在长而复杂的类型的情况下(例如ClassA< ClassB< ClassC,ClassD<ClassE> >)--在这里,用typedef来包装它是一个天大的好消息。

在C#中,使用using 来代替typedef。

唯一可能的是通过定义 类型定义的硬壳变体,它充满了一些问题。


2.命名空间:命名空间

这个话题最近已经讨论过了。对我来说,这真的很奇怪,为什么它还没有被实现,因为它是该语言的一个必须的功能。特别是考虑到社区、代码库和团体发展的趋势。在这种情况下,名称匹配的问题变得非常重要。

他们举了一个例子,即使某个函数里面的局部变量的名称 与另一个文件中定义的类型的名称 相同,编译器也会产生一个错误。这是一种愤怒的行为。

一般来说,在一个空间里把所有东西都堆在一起是不对的。


没有它,用户定义的 类型本质上是不完整的,灵活性大大降低。
假设你已经创建了一个存储时间的结构DATETIME,你希望能够把它作为数据时间使用,把它传递给所有接受数据时间的函数,以及在带有数据时间的表达式中使用它。
通常情况下,这样做很简单:用相应的类型重载构造函数和铸造语句,你就可以得到我们的结构与这个类型的完全兼容。

但在MQL中,有必要创建一个单独的to_datetime() 方法,并将其调用写入各处。或者对DATETIME & type的目标函数的调用必须是重载的,这也不能增加舒适性和灵活性。


4.多接口......嗯,已经有很多关于它的传言和讨论了(我记得三年前他们在服务台写道,工作正在进行中),但它被拖了下来......如果它是在进行的话。



5.支持结构的接口 对于OOP的统一工作是必要的。 目前,我们常常不得不做拐杖。

这个功能可以通过两种方式实现:要么像C#那样--通过打包/解包(装箱),要么以更灵活的方式--为结构创建一个动态句柄,链接到包含该结构的动态对象的描述符--这样会更有效率,另外你可以创建指向结构和其他数据类型的指针,这将增加灵活性。


6.有可能按值传递结构,这在传递小结构(上面例子中的DATETIME)时很重要,如果结构的构造函数支持这种类型,这将允许从一种类型到另一种类型的灵活转换。当通过引用传输时,没有这样的灵活性,尽管如果结构的接口被实现,它将变得不那么重要。


7.有可能指定模板的数字参数。

至于第二个例子,在MQL4中,你可以不这样做,因为那里的函数接受任何尺寸的数组。而在MQL5中,多维数组的一切都要复杂得多。


8.模板的专业化(为特定类型单独实现)。

功能实例。

以一个班级为例。



等等的小事。


9.可以将指针数组(显式或隐式)转换为基指针数组。在以前的构建中,这很有效,而且非常方便。

现在我们不得不重新拷贝阵列到一个新的阵列中,然后再回来,浪费了很多精力。

10.对象引用铸造:(类型&)对象

这是必要的,以便能够将一个被引用的对象传递给一个函数。下面的例子要求将B类的一个对象作为基类A的一个对象写入文件,但现在不能这样做,必须创建一个中间函数,或者将该对象复制到一个新的对象中。


11.不仅用常量初始化数组和结构,而且用任何表达式初始化。这 大大减少和简化了这种情况下的代码。


12.有可能明确地将一个指针投到一个数值上。

现在,只有通过转换为文本形式才能得到一个数字值,这就扼杀了整个想法。

13.设置默认的模板参数

我支持。

Koldun Zloy  
Georgiy Merts:

在我看来,只有极少数人需要这一切。

从Kodobase的代码来看--95%的用户很少使用OOP。而在剩下的5%的大多数人中--所有这些功能都很少使用。当然,它们是好的,甚至可以是有用的,但在我看来,没有很大的必要进行所有这些改进。

这一小部分人可以编写所有人都会使用的库。

Koldun Zloy  

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.关键词朋友。

对于一些类,想给私人成员的访问权,给某个特定的类,但不给所有的。

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
secret  
他们甚至没有路标)还有什么比这更根本的呢?)
Alexey Volchanskiy  
Alexey Navoykov:

我决定创建这样一个话题,因为根据我的观察,MQL语法的发展已经停滞了很久,我不知道开发者是否会改进这种语言,但似乎它仍然缺乏许多功能,其中一些是至关重要的。

在这个主题中,我决定汇编主要的愿望,首先我将给出我的清单,也许有人会补充一些其他的东西。 然后也许开发者会联系并表达他们的愿景,这将是非常好的。

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

预计会被禁止,批评经文是不允许的 :)

PS:改进是有的,不是那么全面,但也有

Alexey Volchanskiy  
secret:
他们甚至没有指针)还有什么比这更根本的呢?)

不会有的,语言是可以管理的,尽管没有GC。

夏普也只有在不安全模式下才有。

Alexey Volchanskiy  
Alexey Navoykov:

是的,我明白,但除了kodobase,还有Freelance和Market,那里的MQ一定对产品的质量感兴趣。 而语言的质量会以某种方式影响开发和调试的质量和速度。

如果像这样谈论百分比,那么为什么一开始就创建了MQL5? 我们仍然会坐在老式的硬核MQL4中,OOP或其他任何东西都不需要。99%的用户对其表示满意 )

也许正常的程序员不会去用MQL,因为它仍然是一种不完整的语言。

Kodobase根本就是95%的垃圾。我已经很久没有看到MT5的新版本了。雷纳特,我记得,承诺在新版本中会有一些全球性的东西。

Alexey Navoykov  
Alexey Volchanskiy:

PS:有一些改进,不是那么全面,但有

我记得的最后一件事是一个允许复制动态对象的隐式复制操作符,但这不算什么,尤其是自那时以来已经过去了很多时间。

原因: