Order of GetChildren/FindFirstChild is not straightforward

The general knowledge people assume for the order of children is based on the order in which they were parented. The wiki even validates this incorrect assumption:

The children are sorted by the order in which their Parent property was set to the object.
source: GetChildren

And the FindFirstChild method (and friends) implicitly refer to this order by mentioning that it returns the first child.

As such, and is from my understanding common knowledge up until this point, people expect the order of GetChildren to always hold the invariant that children parented last always come at the end. This is NOT TRUE. If you remove a child (i.e. reparent it) and the parent has MORE THAN 20 children, Roblox will do a “quick remove” and the order returned by GetChildren is not the order that the wiki suggests.

Reproduction:

local m = Instance.new("Model")
local c = {}

for i = 1, 21 do
    c[i] = Instance.new("Part", m)
    c[i].Name = "Part"
    Instance.new("IntValue", c[i]).Value = i
end

for _, child in ipairs(m:GetChildren()) do
    print(child.Name)
end

c[1]:Destroy()

print(m:FindFirstChild("Part").Value.Value) -- prints 21, not 2
print(m:GetChildren()[1].Value.Value) -- prints 21, not 2

I don’t suggest this functionality be changed otherwise removing children will be slower for instances with more than 20 children, however this needs to be documented. Better yet, it should probably be documented never to rely on the order returned by GetChildren or FindFirstChild.

Additionally, this opens a new medium that exploiters can take advantage of: if a character has more than 20 children and has a UGC item or something called “Humanoid”, then destroy any other object (which will replicate to the server, at least from my testing in studio), which can probably cause that to become the item returned from an expression like character:FindFirstChild("Humanoid") which is widespread and can cause server scripts to error.

4 Likes