Hey MT4 programmers,
(To other programmers, I would appreciate feedback about the solution I came up with to the following problem. If I'm wrong, or there's a better way, please let me know. I have a question about performance and memory at the end. I'm happy to learn as well as educate others).
I was debugging a program I wrote that processes objects and was frustrated that it didn't seem to process every object with each tick. Then I realized a basic misunderstanding on my part about the way that ObjectName(i) references objects. I have noticed that several other programs make this same basic mistake. For many of them, it doesn't matter because the next tick eventually will process the object... but some programs are more sensitive to the issue and may NEVER process an object, which leads to hairloss by the programmer... (tearing it out!) ... until he/she figures out the following:
Assume that you have 4 objects named "A", "B", "C", "D"
The above works perfectly fine if you do not do ObjectDelete or ObectCreate. The list-of-objects is not changed by the program. It will readily process each object and the output would be:
i= 0 ObjectName(i)= A
i= 1 ObjectName(i)= B
i= 2 ObjectName(i)= C
i= 3 ObjectName(i)= D
Notice the output order is alphabetical! This is a big clue as to what the problem is if you do ObjectDelete or ObjectCreate... because your reference to ObjectName(i) will change!
Now suppose that the code does:
The output is:
i= 0 ObjectName(i)= A
i= 2 ObjectName(i)= D
Hey, wait a minute! I know I deleted "B", but what happened to "C" ??? It was not processed! And why are there only 2 objects when I know I have 3 objects left?
Well, duh (after much hairloss), there are two problems. My "for" loop was:
for (int i=0; i< ObjectsTotal(); i++)
The "ObjectsTotal()" is calculated EACH time. When I deleted "B", the number of objects decreased by 1. The program only did 3 loops rather than 4 for each of my original 4 objects.
The second problem, though, is why did it say "D" instead of "C"? The answer is that the command "ObjectName(i)" references (in effect) a dynamic sorted array, not a static array. The order changes based on the objects you delete or create. When "B" was deleted, the order-of-objects became "A", "C", "D" and since "D" is now ObjectName(2), that's what got processed.
You can well imagine that doing ObjectCreate affects the list as well. If I create an object "AA", it becomes the new ObjectName(0), effectively bumping all the others down the list, in which case the program might process the same object 2 (or more) times per each tick.
My solution is to use a global static objectNames[] array and a global static obj_total at the start of my loop. If the program deletes an object, or creates an object, I take care of that too:
Now a question for the experts: Is my use of a global myObjectNames[] array better or worse for performance and memory compared to using a local array inside the start() function? Advantages and drawbacks? I am doing ArrayResize each tick to adjust the array size. I assume I can downsize an array (when there are fewer objects) as easily as upsize it (when there are more). I see no need to initialize unused values back to blank because I'm explicitly setting every array element that I reference.
Thanks for any feedback,
Pips4life (Kent)
(To other programmers, I would appreciate feedback about the solution I came up with to the following problem. If I'm wrong, or there's a better way, please let me know. I have a question about performance and memory at the end. I'm happy to learn as well as educate others).
I was debugging a program I wrote that processes objects and was frustrated that it didn't seem to process every object with each tick. Then I realized a basic misunderstanding on my part about the way that ObjectName(i) references objects. I have noticed that several other programs make this same basic mistake. For many of them, it doesn't matter because the next tick eventually will process the object... but some programs are more sensitive to the issue and may NEVER process an object, which leads to hairloss by the programmer... (tearing it out!) ... until he/she figures out the following:
Assume that you have 4 objects named "A", "B", "C", "D"
Inserted Code
int start() {... //The most common style of a for-each-object loop: for (int i=0; i< ObjectsTotal(); i++) { string objName = ObjectName(i); // Perform operations on objName... ... // However, the BIG questions to ask are: // Does your code do ObjectDelete(objName) or ObjectDelete(otherName) ? // Does your code do ObjectCreate(newName, ...) ? ... Print("i= ", i, " ObjectName(i)= ", objName); }
i= 0 ObjectName(i)= A
i= 1 ObjectName(i)= B
i= 2 ObjectName(i)= C
i= 3 ObjectName(i)= D
Notice the output order is alphabetical! This is a big clue as to what the problem is if you do ObjectDelete or ObjectCreate... because your reference to ObjectName(i) will change!
Now suppose that the code does:
Inserted Code
if (objName == "B") ObjectDelete(objName);
The output is:
i= 0 ObjectName(i)= A
i= 2 ObjectName(i)= D
Hey, wait a minute! I know I deleted "B", but what happened to "C" ??? It was not processed! And why are there only 2 objects when I know I have 3 objects left?
Well, duh (after much hairloss), there are two problems. My "for" loop was:
for (int i=0; i< ObjectsTotal(); i++)
The "ObjectsTotal()" is calculated EACH time. When I deleted "B", the number of objects decreased by 1. The program only did 3 loops rather than 4 for each of my original 4 objects.
The second problem, though, is why did it say "D" instead of "C"? The answer is that the command "ObjectName(i)" references (in effect) a dynamic sorted array, not a static array. The order changes based on the objects you delete or create. When "B" was deleted, the order-of-objects became "A", "C", "D" and since "D" is now ObjectName(2), that's what got processed.
You can well imagine that doing ObjectCreate affects the list as well. If I create an object "AA", it becomes the new ObjectName(0), effectively bumping all the others down the list, in which case the program might process the same object 2 (or more) times per each tick.
My solution is to use a global static objectNames[] array and a global static obj_total at the start of my loop. If the program deletes an object, or creates an object, I take care of that too:
Inserted Code
string myObjectNames[]; // This is a global array variable int obj_total; // This is a global variable int start() { // Create the total list of objects obj_total = ObjectsTotal(); ArrayResize(myObjectNames, obj_total); for(int h = 0; h < obj_total; h++) myObjectNames[h] = ObjectName(h); // Now process the list of objects for(int i = 0; i < obj_total; i++) // for each object, do... { string objName=myObjectNames[i]; // References a static array if (ObjectFind(objName) < 0) continue; // If the object was deleted before // processing, skip to the next obj // Perform operations on objName... ... // The code can do ObjectDelete(objName) or ObjectDelete(otherName) // If the code does ObjectDelete(objName) and ObjectCreate(objName), // there's usuallyno need to change the myObjectNames[] array, nor obj_total. // However, if you do ObjectCreate(newName, ...) where newName // does not exist, then to process it this tick, you might want to do: obj_total++; ArrayResize(myObjectNames, obj_total); myObjectNames[obj_total -1] = newName; ... Print("i= ", i, " myObjectName[i]= ", objName ); }
Now a question for the experts: Is my use of a global myObjectNames[] array better or worse for performance and memory compared to using a local array inside the start() function? Advantages and drawbacks? I am doing ArrayResize each tick to adjust the array size. I assume I can downsize an array (when there are fewer objects) as easily as upsize it (when there are more). I see no need to initialize unused values back to blank because I'm explicitly setting every array element that I reference.
Thanks for any feedback,
Pips4life (Kent)