IsDescendantOf(nil) should throw an error

As a Roblox developer, it is currently too hard to debug code that gives IsDescendantOf() a nil value. This is because, intuitively, I would expect the method to throw an error if given the wrong type. Instead, it simply returns true for every object, leading me to second-guess other parts of my codebase that are not the culprit.

This behavior is documented so it is presumably intentional, but it is so unintuitive I initially assumed it was a bug and filed a bug report:

If this behavior is not intentionally relied upon by any games (which I assume to be the case since a statement that returns “true” 100% of the time is effectively worthless) I recommend it be changed to throw an error.

If Roblox is able to address this issue, it would improve my development experience because I’d be able to catch mistakes I make with IsDescendantOf() much faster.

2 Likes

Out of curiosity, why do you think erroring is more intuitive than x:IsDescendantOf(nil) being equivalent to not x:IsDescendantOf(game)?

2 Likes

I suppose it’s because that behavior wouldn’t technically be correct, since theoretically all objects are indeed a descendant of nil. We also already have that not x:IsDescendantOf(game) expression if we want to check if an object is in the datamodel, so an equivalent to that wouldn’t serve much purpose. Considering all that, I think throwing an error is the best case because it’s the most useful to the developer.

1 Like

the type annotation of IsDescendantOf implies that IsDescendantOf always expects an Instance, nil is obviously not of type Instance so it should just error with something like “Argument 1 missing or nil”.

4 Likes

I disagree, because objects can be children and descendants of nil, if nil is their Parent. Come to think of it, that’s probably why that method returns true - something up in the Instance tree (the DataModel iirc?) has a nil parent.

However, nil has a different meaning when it comes to instances. Usually it’s associated with destroyed or removed instances. This is why for me, it’s intuitive that nil is treated as a separate entity, so x:IsDescendantOf(nil) returns true only if x.Parent == nil.

Both my and your proposals would probably break a huge number of games though, so I don’t expect a change to be made here.

I don’t agree with you here

an easier way to catch this is by using t a runtime type checker library, as i don’t think it is worth changing behavior of this

i think the problem here is due to lack of knowledge, by knowing that nil is a parent of game you’d understand that it is correct behavior, though i agree that it is not intuitive

I believe IsDescendantOf(nil) returning true is the proper and correct logic. A Parent can either be an Instance, or it can be nil. At a certain point in the ancestry, every object is a descendant of nil; and so the current implementation makes perfect sense.

This method has existed since the dawn of the API. Altering it now, to start rejecting nil inputs, would be a breaking change for countless algorithms. Consider if a scripter wanted to treat a variable Instance as a blacklist. They might thereby write:

if not Object:IsDescendantOf(Blacklist) then
	-- Only if Blacklist has been defined, and Object is not a part of it
end

In these cases, doing nothing until Blacklist has been defined–or otherwise intentionally setting Blacklist to nil as a means of excluding everything, may be entirely desirable.