Is it possible to implement a singleton pattern in MQL4. - page 9

 
hoz:

I've done it this way:

But for some reason there are a lot of errors when compiling. What's wrong?

Trying to transfer a rather simple Singleton by Myers to MQL4++ could look like this, for example:

#property strict

/******************************************************************************/
class Symbol_Properties {
private:
   // Реализация технической части singleton'а
  /******************************************************************************/
public: // Вечно в этом MQL4++ что-то не работает: 'Symbol_Properties::Symbol_Prope…' - cannot call private member function
  Symbol_Properties() {};
private: // Восстанавливаем private
  Symbol_Properties(const Symbol_Properties &p);
  void operator =(const Symbol_Properties &);

public:
  static Symbol_Properties *singleton() {
    static Symbol_Properties sp;
    return GetPointer(sp);
  }

  // Пользовательская часть singleton'а
  /******************************************************************************/
  datetime    gdt_Quote;           // Время поступления последней котировки
  double      gda_Price [2];       // Текущие рыночные цены (0 - Bid, 1- Ask)
  double      gd_Spread;           // Размер спреда в пунктах
  double      gd_Swap;             // Своп
  double      gd_Comission;        // Комиссия
  double      gd_Pt;               // Величина одного пункта
  int         gi_Digits;           // Количество знаков в цене после запятой
  int         gi_StopLevel;        // Минимально-допустимый уровень стоп-лосса/тейк-профита в пунктах
  int         gi_FreezLevel;       // Уровень заморозки ордеров в пунктах
};

/******************************************************************************/
void change() {
  Symbol_Properties *p = Symbol_Properties::singleton(); // Получение singleton'а

  p.gdt_Quote = TimeCurrent();
  p.gda_Price[0] = Bid;
  p.gda_Price[1] = Ask;
}

/******************************************************************************/
void OnStart() {
  Symbol_Properties *p = Symbol_Properties::singleton(); // Получение singleton'а

  Print("gdt_Quote = ", p.gdt_Quote, ", Price = ", p.gda_Price[0], "/", p.gda_Price[1]);
  change();
  Print("gdt_Quote = ", p.gdt_Quote, ", Price = ", p.gda_Price[0], "/", p.gda_Price[1]);
}

Execution result:

01:24:57 Script 3 EURUSDm,H1: loaded successfully
01:24:57 3 EURUSDm,H1: initialized
01:24:57 3 EURUSDm,H1: gdt_Quote = 1970.01.01 00:00:00, Price = 0.0/0.0
01:24:57 3 EURUSDm,H1: gdt_Quote = 2014.09.03 21:24:57, Price = 1.31461/1.3148
01:24:57 3 EURUSDm,H1: uninit reason 0
01:24:57 Script 3 EURUSDm,H1: removed

A static method singleton() creates a static variable of type Symbol_Properties, but at compile time a NOT valid default constructor call access error is generated, because the method, although static, - has access to all members, including private. Therefore, due to bug in MQL4++ implementation this constructor had to be placed in public. If they fix it, we won't have to do it anymore.

The result of the execution shows that the data has changed after the change() call. This indirectly indicates that the change() function has received the address of the same object inside itself that was also received in OnStart().

Due to the error in MQL4++ this is no Singleton at all, since the default constructor is public, so many such objects can be created. If error is corrected, and after default constructor is placed in private section, it will become full-fledged implementation of Myers' Singleton in MQL4++.

 
ALXIMIKS:

You haven't figured out in two days that static behaves differently in stuct and class?

the structures seem to be taken from c and only a little bit pumped up in terms of inheritance,

As for classes, they are full-fledged.

Because of this, you don't have to reserve space for a static variable in structures

but you have to reserve space in classes, otherwise you won't:

Not true, this wonderful MQL4++ compiler behaves differently. As soon as you create an object instance, the behaviour "aligns":

#property strict

/******************************************************************************/
struct A {
  static int x;
};

/******************************************************************************/
void OnStart() {
  A y;
}

For some reason it doesn't compile (the first and third are warnings, but the second is a full-fledged error):

struct has no members, size assigned to 1 byte
unresolved static variable 'A::x'
variable 'y' not used

So is it necessary to reserve "space for a static variable" in structures?

And in the next version of the terminal/compiler, will it be the same (well, so as not to rush to fix everything written before when changing version)?

 
TheXpert:

I forgot about encapsulation. And it can be deleted. And there are no constant pointers here.) In fact, singleton is not the best pattern.

And templates are good, at least some are. For classes, probably only a dream.



Well, whether it is the worst or the best, I will not judge.

Let me remind the participants of this discussion that the above mentioned MEMORY MANAGEMENT MODES - Automatic, Dynamic, Static, Based - do not apply to templates, no matter how mighty OOP is.

 
Так обязательно ли резервировать в структурах "место под static-переменную"?
"Yes", it's just a point that you can also do "no", but you shouldn't do it that way.
 
simpleton:


Now, because of bug in MQL4++, this is not a Singleton, because many such objects can be created, because the default constructor is public. If error is corrected and default constructor is placed in private section, it will become full-fledged Singleton implementation in MQL4++.


Thank you, I didn't know I could take a pointer here.

The code is messed up, it could be simpler, sorry there are no templates.

I can't put the code in ((

class Singleton{

private:

class SomeClass{

public:

int a;

};

Singleton(){}

~Singleton(){}

public:

static SomeClass* Instance(){

static SomeClass a();

return GetPointer (a);

}

};

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance();

some_ptr.a = 5;

Alert(some_ptr.a);

}

 
ALXIMIKS:


Thanks, didn't know you could take a pointer here.

You're messing with the code, it could be simpler, sorry there are no templates.

I can't get the code to work ((

class Singleton{

private:

class SomeClass{

public:

int a;

};

Singleton(){}

~Singleton(){}

public:

static SomeClass* Instance(){

static SomeClass a();

return GetPointer (a);

}

};

void OnStart()

{

SomeClass* some_ptr = Singleton::Instance();

some_ptr.a = 5;

Alert(some_ptr.a);

}

Here is Myers' code for C++:

class Singleton
{
private:
    Singleton() {}
    Singleton( const Singleton&);
    Singleton& operator=( Singleton& );
public:
    static Singleton& getInstance() {
        static Singleton  instance;
        return instance;
    }
};

And here is the same code transposed into MQL4++, which is the technical part of the class in the example:

class Symbol_Properties {
private:
   // Реализация технической части singleton'а
  /******************************************************************************/
public: // Вечно в этом MQL4++ что-то не работает: 'Symbol_Properties::Symbol_Prope…' - cannot call private member function
  Symbol_Properties() {};
private: // Восстанавливаем private
  Symbol_Properties(const Symbol_Properties &p);
  void operator =(const Symbol_Properties &);

public:
  static Symbol_Properties *singleton() {
    static Symbol_Properties sp;
    return GetPointer(sp);
  }

Where is the "wizardry" here?

Your example exploits errors of the MQL4++ compiler, in particular, the use of SomeClass type in OnStart() is inappropriate, because this is a nested type of the Singleton class, and the "adult" compiler instantly detects an error:

try.cpp:33:9: error: unknown type name 'SomeClass'
        SomeClass* some_ptr = Singleton::Instance();
        ^

However, this is not a crucial point, as a nested type can be specified correctly. What is more important is that the SomeClass type is declared in the private section of the Singleton class, and therefore using SomeClass in OnStart() is now fundamentally wrong, which the "adult" compiler immediately reports:

try.cpp:33:20: error: 'SomeClass' is a private member of 'Singleton'
        Singleton::SomeClass* some_ptr = Singleton::Instance();
                   ^

Your implementation will work unless the MQL4++ compiler fixes the access control bacchanalia.

 

1. Maerse, not Maerse, what the fuck does it matter if the code works and does the right thing without errors in MQL and not in ++.

2. Does your code do what it should? No, it does not. You have already understood everything.

My example shows the handling of errors (with respect to C++) in MQL. If something is not convenient, see points 1 and 2.

4. As for creating a pointer to a private class, yes, it is an MQL error, but there is no auto to identify the type, so it is good that it works. \

(p.s. I may have overdid it at the expense of auto, I should check it)

5. I haven't found any way in MQL to dereference a pointer in order to get an object, therefore I consider private copy constructor and assignment operator superfluous.

Try to use them, I'll be happy to see the way))

 
ALXIMIKS:

1. Maerse, not Maerse, what the fuck does it matter if the code works and does the right thing without errors in MQL, not in ++.

2. Does your code do what it should? No, it does not. You have already understood everything.

My example shows the handling of errors (with respect to C++) in MQL. If something is not convenient, see points 1 and 2.

4. As for creating a pointer to a private class, yes, it is an MQL error, but there is no auto to identify the type, so it is good that it works. \

(p.s. I may have overdid it at the expense of auto, I should check it)

5. I haven't found any way in MQL to dereference a pointer in order to get an object, therefore I consider private copy constructor and assignment operator superfluous.

Try to use them, I'll be happy to see the way))

1. Now - it does, but NOT the way (explanation below).

2. If they don't fix it - it won't do either. And unlikely to be implementable at all.

3. It's not a way around bugs, it's exploitation.

4. There's a lot that isn't there.

5. Such things may be possible in this version, in particular, I think I've flashed that the copy constructor is not synthesized, but that doesn't guarantee that it won't start synthesizing in future versions. The overhead of declaring them, on the other hand, I think is negligible.

Now to explain why your code not only has the potential problems I mentioned in the previous post, but also why it is not in principle a singleton and won't be, and whether they fix the access bacchanalia or not:

#property strict

class Singleton{
private:
         class SomeClass{
         public:
            int a;
         };
        Singleton(){}
        ~Singleton(){}   
public:
        static SomeClass* Instance(){
                        static SomeClass a;
                        return GetPointer (a);
                }
        };
        int i;

void OnStart()
{       
        SomeClass* some_ptr = Singleton::Instance();
        SomeClass obj1;
        SomeClass obj2;

        obj1.a = 3;
        obj2.a = 7;

        some_ptr.a = 5;
        Print("some_ptr.a = ", some_ptr.a);          
        Print("obj1.a = ", obj1.a);          
        Print("obj2.a = ", obj2.a);          
}

This code is quite successfully executed:

10:09:27 Script 3 EURUSDm,H1: loaded successfully
10:09:27 3 EURUSDm,H1: initialized
10:09:27 3 EURUSDm,H1: some_ptr.a = 5
10:09:27 3 EURUSDm,H1: obj1.a = 3
10:09:27 3 EURUSDm,H1: obj2.a = 7
10:09:27 3 EURUSDm,H1: uninit reason 0
10:09:27 Script 3 EURUSDm,H1: removed

Do you see how many singleton's have managed to be created, while they ONCE exist?

Would anything in this sense change for your code if the access bacchanal were fixed?

Will it change in my code?

Do you think that the more unapologetic you make your point, the more correct it will be?

 

Yes, thank you for your attention, you're right, it's not a singleton in this variant either.

Concerning implicit constructors and operators - make them explicit and try to use them, it seems to me they won't work because of impossibility to dereference the pointer to the object

Why doesn't it work, 'ptr' - cannot call protected member function :

class smart_ptr{
            Singleton* ptr;
      public:        
            smart_ptr(Singleton* val): ptr(val){}          
            smart_ptr(): ptr(NULL){} 
            ~smart_ptr(){delete ptr;}
      };
 
ALXIMIKS:

Yes, thank you for your attention, you're right, it's not a singleton in this variant either.

Concerning implicit constructors and operators - make them explicit and try to use them, it seems to me they won't work because of impossibility to dereference the pointer to the object

Why doesn't it work, 'ptr' - cannot call protected member function :

It doesn't seem to work and there are many more bugs here. It's a pity that very few people notice it. I don't want to get into an argument, but actually there is a huge difference. Some things that apply to structures in C++ don't work in MKL4. But I'll keep silent... otherwise they will start asking questions like:

"Why do I need it".

If only so that I could not get into an unfinished textbook, but simply write things that work in C++ in MKL4 and not think whether they work here or not. I don't need anything else at this stage...