Loop change at new version

H all,
I finally upgraded to the new version :smiley:
Something strange happened, and I’m not sure it’s actually a bug.

I have a custom function that I use extensively.
It takes two objects and merges them, with support for deep recursion.

After updating to the new ZIM version, the function only worked partially.

With small objects, it overwrote everything without any issue, but with large objects it didn’t traverse all the internal values.
It’s worth noting that I was running it on a very large and complex object.

After I changed the loop to a forEach that iterates over the object’s keys, the function worked correctly.

Is it possible that something changed in the loop behavior?
Maybe there’s some limitation on how many times it can recurse or iterate inward?

Hi @racheli - what version was the loop working on for you and we can do a comparison. Also, any error in the console? The loop uses for loops in behind... so there is no limit. Also, can you paste the code in here so we can test. What kind of objects are you traversing? Let's figure this out.

I used 018 version.

this is the function:

   static replaceOnObject(obj, overObject, saveArr) {
      if (zot(saveArr)) saveArr = [];
      var pp = this;

      // החלפת loop() ב-Object.keys().forEach()
      Object.keys(overObject || {}).forEach(function(item) {
         if (typeof obj[item] != "object") {
            var isSave = false;
            loop(saveArr, function (saveItem) {
               if (saveItem == item) {
                  isSave = true;
               }
            });
            if (!isSave) {
               obj[item] = overObject[item];
            }
         } else {
            if (Array.isArray(overObject[item])) {
               obj[item] = overObject[item];
            } else {
               pp.replaceOnObject(obj[item], overObject[item]);
            }
         }
      });
   }

I used this function to override a design-specific json with the default json.
These are very large and complex objects.

We just did a comparison, and yes, there is a difference that could possibly affect the outcome. We did not test it very well, so perhaps we missed something:


// this test is the same in both versions
var type = typeof obj=="number"?"number":(Array.isArray(obj)?"array":(obj.constructor === {}.constructor?"object":(obj instanceof NodeList?"nodelist":(typeof obj == "string"?"string":(obj instanceof HTMLCollection?"htmlcollection":(obj.type&&obj.type=="Dictionary"?"Dictionary":"invalid"))))));


// This test was added in ZIM 019
if (type=="invalid" && obj.children && obj.children instanceof HTMLCollection) {
	type="htmlcollection";
	obj = obj.children;
}

// and this test added the Tile in ZIM 019
if ((obj.type == "Container" || obj.type == "Tile") && !obj.addChild) {
	return undefined;
}

We have made a https://zimjs.org/cdn/019/zim_doc_racheli.js that has all of the ZIM 019 except we put the ZIM 018 tests back in at the top of the loop. Could you insert this file rather than the 019 file - it will mean that you need to go back to scripts rather than the ES6 module. If you need a hand, let us know.

Nice to have a ZIM version with my name :laughing:
I tested it, but unfortunately it still doesn't work well.

1 Like

Okay - interesting. There are a couple additional loop parameters that should not affect the looping... but I have replaced the complete loop code with the 018 loop code and saved it as https://zimjs.org/cdn/019/zim_doc_racheli2.js

Yes!!!
Now it works corretly!
Do you have a hypothesis as to what the difference there is that causes this?

Well, if that works, it should be easy to figure it out. I am out for a bit but will send a couple other versions in a couple hours.

1 Like

Oh - lost the thread. Will do it now...

Okay - looking at the first test I sent you, I think I did it wrong. I had made a loop2 and was adjusting that. So here is https://zimjs.org/019/zim_doc_racheli3.js to try. Let us know.

Great, but the link is not working.

Ah... sorry - forgot the cdn/ https://zimjs.org/cdn/019/zim_doc_racheli3.js

Yes, it works corretly!

okay - then it is something in that little new part we added. That is good because I looked at the extra monitor code (the other code we added) and could not see what would cause the problem. Here is the changed code. Do you know what kind of object is missing from the loop?

// new code (skipping something)
if (type=="invalid" && obj.children && obj.children instanceof HTMLCollection) {
	type="htmlcollection";
	obj = obj.children;
}

if ((obj.type == "Container" || obj.type == "Tile") && !obj.addChild) {
	return undefined;
}
// old code (working)
if (type == "container" && !obj.addChild) {
	return undefined;
}

I have made https://zimjs.org/cdn/019/zim_doc_racheli4.js and that puts back the original working conditional but keeps the htmlCollection code. Can you try that out and let us know how it goes. So version 4 has the following code:

if (type=="invalid" && obj.children && obj.children instanceof HTMLCollection) {
	type="htmlcollection";
	obj = obj.children;
}

// if ((obj.type == "Container" || obj.type == "Tile") && !obj.addChild) {
// 	return undefined;
// }

if (type == "container" && !obj.addChild) {
	return undefined;
}

I tested it and with this version(ZIM_doc_racheli4.js) it also works corretly!
I tried to debug the code but I can't find the missing object in the loop.

That's weird. I can't even remember why would need that test. A Container and a Tile should always have an addChild method. But obviously, recently, there was a need for it.

Maybe we can see what it is - sorry... try https://zimjs.org/cdn/019/zim_doc_racheli5.js

if ((obj.type == "Container" || obj.type == "Tile") && !obj.addChild) {
	zogr(obj)
	zogb(obj.type)
	return undefined;
}

No need to apologize — I’m the one interrupting you, and because of me you’re doing all these checks.
Thanks a lot :pray:.
I tested the version, and with this version the object overriding doesn’t work correctly for me.

Yes, version 5 is broken, but does it zog in red and blue the object and object type that might be missing or triggering the undefined? Which I think means it gets skipped in the loop.

When you get a chance, let us know if it zogs the object that might be missing... thanks.

Ahhh, now I understand!!

The code breaks on this line:

if ((obj.type == "Container" || obj.type == "Tile") && !obj.addChild) {
    zogr(obj)
    zogb(obj.type)
    return undefined;
}

Because in the override object there really is a key named "type" with the value "Container".

Here is an example of an object where the loop stops midway:

{
    "language": "he",
    "theme": "light",
    "type": "Container",
    "notifications": {
        "email": false,
        "push": true,
        "sms": true
    }
}

Because of the line:

"type": "Container",

it does not continue to go inside.

Is there an easy way to check that the incoming object is actually a Container, and not just an object that happens to have a type property with the value "Container"?

And again, thank you very much for your help!!