"X is not a valid member of Y" when using the "not" operator?

  1. I want to check if a part is not within the workspace using the “not” operator.

  2. ROBLOX throws an error when the part is not found within the workspace.

Why is this a thing? Simply go into studio, write a short line if not workspace.somepart then print("not part") else print("part") end and run a test. It will error saying that somepart is not a valid member of workspace, but that’s literally what you’re checking for, if it’s not in the workspace?? It’s so counter intuitive and the thing that makes even less sense is that it works if you actually have something named somepart, it prints true in that scenario.

How can you check if a part is NOT in the workspace using the “not” operator if it just errors when it isn’t?

1 Like

Use Workspace:FindFirstChild("somepart") instead of .somepart

if not Workspace:FindFirstChild("somepart") then
    -- do logic
end

The workspace.somepart is modified by Roblox itself to error when the child isn’t there so you don’t get a more obscure error.

Edit: Provided a few more details.

3 Likes

u coding in english bro?

The whole point is, roblox throws an exception when you try indexing for something that doesn’t exist. It’s not like this behaviour magically changes by applying a not.

Use instead :FindFirstChild. So not workspace:FindFirstChild("somepart")

1 Like

And also @Quenty,

https://gyazo.com/62f2ebed4acdd139948585d4c3b6e593 the regular “not” in lua seems to work like that, actually printing FALSE if something does not exist.
Besides, “FindFirstChild” throws an infinite yield warning. I’ve tried it, should have mentioned that in the thread.

No,that’s :WaitForChild when you do not provide the timeout argument and it’s been waiting for a while.

1 Like

Whenever you try to access a property of some object, the normal behavior is to throw an error if that field doesn’t exist. Roblox does this with all objects, for something like a table though you’d have to implement that behavior yourself with metatables. For tables, the default behavior is just to return nil; so you can just do if not someTable.prop then

1 Like

Oh yeah, I actually wrote WaitForChild instead of FindFirstChild. Sorry, and thanks. Still, it’s pretty confusing to see normal lua work like that and it being different on ROBLOX with no indication.

1 Like

@incapaxx is correct, the infinite yield warning is for WaitForChild. :stuck_out_tongue:

Basically, and this may be confusing, what’s happening is Roblox is setting a metatable on the table to error.

So what we’d get here is something like this:

local fakeWorkspace = setmetatable({}, {
    __index = function(self, index) -- operation on indexing when nothing is there. 
        error("Bad index")
    end;
end

fakeWorkspace.blah --> Error: Bad index

So basically order of operation is

  1. Check index
  2. Roblox managed code throws error
  3. Not/if branch is never executed

But if we didn’t have this, we’d have something like this:

  1. Check index
  2. Return nil
  3. not nil = true
  4. If statement evaluated if true then
  5. Your code executes

Basically, because Roblox adds an error automatically on indexing when nothing exists, instead of returning nil, you have to use FindFirstChild.

This is good behavior.

1 Like

Look here I’ll show this example so you see the issue.

local t = setmetatable({ a = 0 }, { __index = function(_, key)
    error(key .. " is not a valid member of t", 2)
end })
print(t.a) --> 0
print(t.b) --> b is not a valid member of t

You can implement roblox’s behaviour more or so like that. Roblox did NOT change the behaviour of the not operator. The issue is, you’re still indexing. The reason it works fine on just tables is because their metatable (if they have one) __index function (if it points to one) is probably not written to throw exception on nonexistent keys.

I guess if anything this is really a lesson in order of operations.

Another big gotcha with not statements is doing something like this

if not thing and thing:FindFirstChild("OtherThing") then
     -- do things
end

vs.

if not (thing and thing:FindFirstChild("OtherThing")) then
     -- do things
end

not operations have precedence over and statements, which is what I thought this problem was going to originally be. :stuck_out_tongue: