Checking if descendant exists

I dont know how else to explain this in the title, so just hear me out:

Lets say you want to see if hello exists as one of the descendants of something.
Normally you would do this:

local obj = something.thing.another:FindFirstChild("hello")

To check if it exists, just do

if obj ~= nil then

Right? Well, wrong. If something or thing or another does not exist, that line will error.

So now our code becomes THIS THING: (or alternatively 4 if statements instead of using and)

if something and something:FindFirstChild("thing") and something.thing:FindFirstChild("another") and something.thing.another:FindFirstChild("hello") then

While this works, its super long and clunky, and just feels wrong.
What would be a way to simplify this without making a loooong if statement?

FindFirstChild can be called recursively to find a nested child. Try:
local obj = something:FindFirstChild("hello", true)
which will attempt to find child “hello” anywhere in the children of “something”

Also:
if obj ~= nil is the same logical statement as if obj since “if obj is not nonexistent” is the same as “if obj is existent”

1 Like

Just use Instance:IsDescendantOf(Instance)

While this could work in some cases, it would not in others since there could be multiple instances named “hello”

For instance there might be an object named “hello” in thing but also in another, the one specifically in another is the one we are looking for.

What do you exactly mean by this?
If we made a variable of the object like this:

local obj = something.thing.another:FindFirstChild("hello")

then it would error either way if any of those parents dont exist
So doing something like

if obj:IsDescendantOf(workspace) then

Would not help if the variable already had an error

You could either use

parent:IsAncestorOf(child) or child:IsDescendantOf(parent) to check if a part is a descendant of something.

what about pcalls? im not too advanced in lua, but isn’t that like the lua version of a try and catch in java?

Yeah I mean, it is pretty similar. So using pcalls could work for this situation. But from my understanding of the forum, I think it would be better to just use

if something and something:FindFirstChild("thing") and something.thing:FindFirstChild("another") and something.thing.another:FindFirstChild("hello") then

To make it shorter, just put something:FindFirstChild("thing") and something.thing:FindFirstChild("another") and something.thing.another:FindFirstChild("hello") in variables.

you need this function my friend
usage:

local found,obj = module.hasNested(something,"thing","another","hello")
if found then print("yippe") end
function module.hasNested(parent, ...:string) :(boolean,any)
	local good, result = pcall(function(...)
		for _, childName in pairs({...}) do
			parent = parent[childName]
		end
		return parent
	end, ...)
	if type(parent)=="table" and good and result==nil then --tables don't error on nil members so we need to force a no
		return false
	else
		return good, result
	end
end

or if you don’t want to deal with that you can use

function module.waitForNested(waitTime :number?, parent :Instance, child :string, ... :string) :Instance?
    if not (parent and child) then return parent end
    return module.waitForNested(waitTime,parent:WaitForChild(child,waitTime),...)
end
1 Like

A lot of great suggestions I’ve read. Personally, I’d just wrap it in a pcall because why not.

local success, errormessage = pcall(function()
if something.thing.another:FindFirstChild("hello") then
end
end)
if success then

else print(errormessage)
end

I know it’s not what pcalls are necessarily for, but who’s gonna stop me?

1 Like

The way I deal with this is doing this:

local obj
if something.thing.another:FindFirstChild("hello") then obj = something.thing.another:FindFirstChild("hello") end

then check if it’s nil or not after that
or

if something.thing.another:FindFirstChild("hello") then
    obj = something.thing.another:FindFirstChild("hello")
    -- run rest of code in this
end

the only downside to this is that you are typing out the path to the instance twice, but it’s probably easier than many other options

if something:FindFirstChild("hello", true) then

I guess people forgot about the recursive parameter of “:FindFirstChild()”.

https://developer.roblox.com/en-us/api-reference/function/Instance/FindFirstChild

Never mind, I see the first reply suggested this too.

1 Like