I don’t think it will be any cleaner since it will do the same thing as GetChildren() but also check for classes. If you want to add such a feature in a clean way, then you will probably have to rewrite some pieces of instance source code, which can lead to fatal errors in old places.
There would probably need to be a GetChildrenWhichIsA (Are?) as well, since OfClass methods only looks for that exact class while WhichIsA respects inheritance.
GetDescendants variants would also need to be added, but I’m not too sure how pretty GetDescendantsWhichIs looks.
Way easier in what way? You’ll have to require the module in each script you want to use the method in, and GetChildrenOfClass(parent, classname) just looks weird when all other methods are integrated into the Instance class itself.
local module = { }
function module.GetChildrenOfClass(parent: Instance, className: string, func: (index: number, value: Instance) -> ())
for index, value in parent:GetChildren() do
if value:IsA(className) then
func(index, value)
end
end
end
return module
I really don’t see a use case for this outside of that it would spare you the 20 seconds of writing a conditional :GetChildren() function. I do wonder what it is you’re doing that has you worried about the “expensive” performance impact of :GetChildren().
GetChildren() is just expensive… that’s like, a well known fact. Regardless of use-case, we should all be striving for more efficiency.
Most of the time I’m doing class checking on what’s returned by GetChildren(). It’s a very obvious area for improvement. So it’d be nice if there was a method I could call that would be faster than anything I could code on the developer level.
Also, because it’s returning a smaller array than GetChildren() I would hope that the method itself would run faster as well.
I would say a common case would be querying all the descendant BaseParts for param objects and methods (i.e., RaycastParams.FilterDescendantsInstances & workspace/BulkMoveTo).
This normally is achieved with the following:
local Children: {Instance} = Container:GetChildren() -- 1000 Instances?
local Parts: {BasePart} = {}
for _, Child: Instance in Children do
if Child:IsA("BasePart") then
table.insert(Parts, Child)
end
end
But this is bad because it requires Parts to be resized every time a new index is added and considering that Children could contain thousands of Instances, performance is going to suffer. Yes, we could pre-allocate Parts with table.create(#Children) but that allocation won’t downsize when only a few elements are added, so that’s off the table.
GetChildrenOfClass/WhichIsA gives a predictable and sound implementation of producing a single table that doesn’t require repetitive allocation in user code. I would argue this feature would be less for ergonomic use cases and more of a performant alternative to expensive code like shown above.
I would like if there was a filter callback parameter in the GetChildren method that looks something like this:
Lets say I wanted to get all decals in a Part
local Decals = Part:GetChildren(function(Instance: Instance)
return Instance:IsA("Decal") -- boolean
end)
I don’t believe this would break any games, because why would someone pass a callback as the first argument.
I would say that this is better than adding a bunch of small APIs like GetChildrenOfClass, because people would probably want more of them. Instead just add a filter callback and it allows for anything really.
And this allows for a more “advanced” lookup system. This should also be added to GetDescendants, since they’re basically the same.
Gonna bump this. The lack of a GetChildrenOfClass is still a pain point for myself and other devs, and there’s precedent for something similar in the form of FindFirstChildWhichIsA / FindFirstChildOfClass.
Having a form of GetChildren which only scopes out specific instance types would not only improve readability and cleanliness of code. it’d also possibly be more efficient. GetDescendantsOfClass would also be appreciated!