Tip: How to tell if ObjectValue.Value has been destroyed/is actually nil

Hi, I thought I’d share this to help anybody who had the same problem as me, which was that when a part that is a value of an ObjectValue is destroyed, ObjectValue.Value does not become nil.

So, as an example, if you run this code, it’ll print “part exists,” even though part has been destroyed

local part=Instance.new("Part")
part.Parent=game.Workspace

local objVal=Instance.new("ObjectValue")
objVal.Parent=game.Workspace

objVal.Value=part

part:Destroy()
if objVal.Value~= nil then
          print("part exists")
else
          print("part does not exist")
end

A solution is to, instead of checking if the value is nil, check if the value is a descendant of workspace (or whatever it should be a descendant of)

Here is the example, but using the solution:

local part=Instance.new("Part")
part.Parent=game.Workspace

local objVal=Instance.new("ObjectValue")
objVal.Parent=game.Workspace

objVal.Value=part

part:Destroy()
if objVal.Value:IsDescendantOf(game.Workspace) then
          print("part exists")
else
          print("part does not exist")
end

Anyway, I hope this saves somebody’s time. I know there are other solutions that will work in more situations (like if the part is moved from Workspace to ServerStorage), but this one still has it’s place.

17 Likes

I’ve bin trying to find a solution for this problem for so long thank you so much

I don’t know how something like this isn’t mentioned in the documentation, very helpful tip!

local Part = Instance.new(“Part”)
Part.Parent = game.Workspace
Part:Destroy()
print(Part)

Prints “Part”
The part isnt nil when destroyed (Only the parent property gets changed to nil)

local Part = Instance.new(“Part”)
Part.Parent = game.Workspace

local ObjectValue = Instance.new(“ObjectValue”)
ObjectValue.Value = Part

Part:Destroy()

if ObjectValue.Value.Parent then
print(“Part exist”)
elseif not ObjectValue.Value.Parent then
print(“Part doesnt exist”)
end

This is an better way to do it

local Part=Instance.new("Part",workspace);
local ObjectValue=Instance.new("ObjectValue");
ObjectValue.Value=Part;
Part:Destroy();
print(if ObjectValue.Value.Parent~=nil then "Part exists" else "Part does not exist");

This isn’t reliable; you can’t know when an instance is destroyed simply by checking the presence of a parent. The instance could have been temporarily moved out of the data-model by the developer. The only in-line check you can make for an instance’s destruction is through a function that attempts to set its parent. A destroyed instance’s parent property will be locked, so this attempt will raise an error:

local function isDestroyed(instance: Instance): boolean
    if instance.Parent then
        return false
    end

    return not pcall(function()
        instance.Parent = instance.Parent
    end)
end
if isDestroyed(objectValue.Value) then
    -- ...
end

Ultimately, the more elegant thing to do is hook onto Instance.Destroying when ObjectValue.Value is assigned an instance

It’s not good for practice to use the second parameter in Instance.new()

And why not, what’s the problem with it

There are several reasons why you should prefabricate over using Instance.new

Prefabrication in the context of Roblox scripting refers to the process of creating assets prior to runtime (outside of a script). This means that you would configure and organize the stats folder in Roblox Studio. The advantages of this are as follows:

  1. Bulk removal of boilerplate code.

  2. Ease of configuration; changing the initial state of your values, (re)organization, removing, and adding values is made easier.

  3. Visualization. You can better visualize the structure of your stats folder.

  4. Elimination of early-deployment. I won’t bother explaining the negative effects of early deployment as this article posted by a Roblox engineer covers them well. The image attached below also covers some benchmarks regarding deployment methods.

TL;DR: An asset should not be made a descendant of game until it and its descendants have been fully configured. Many Roblox developers do not do this, and it’s only tedious to go back and tweak the bulk boilerplate code. The associated problems are solved as a latent function of prefabrication

Additional benchmarking:

I’m pretty sure this prints for a little bit because the part is queued for garbage collection. Destroyed instances aren’t immediately cleared from references.

I meant that (I gotta type more because min of letters are 30)