Description
While this may not seem like a bug. It’s an issue I encountered once which I never expected.
There can be a case where an Instance is bound to a ObjectValue, which has yet not been initialized and returns nil
. Even though it’s statically linked. Workarounds exist, but there shouldn’t be.
Additionally there are issues when using “Cut” in Studio on an ObjectValue’s bound instance, and pasting it back. There aren’t issues for cloning ObjectValues.
Theoretically, Engine Developers could fix this, by checking if the referent is available in a ObjectValue, to then replace it automatically. But I’d to bring into awarness that eventually it may break someone elses workflow.
However… another issue related to this is for PLUGINS
Developers can't copy multiple Instances like the Engine can. The Engine is able to re-connect ObjectValue's that have been copied with no Parent container node. Developers don't have this logic by default, and need to implement one by themselves.
You can copy paste things like so:
The Engine is somehow capable of linking the right things back together. We developers can only achieve this by putting both of these things in a Folder and Cloning the Folder. But for Plugins… no chance
for k,v in ipairs(game.Selection:Get()) do v:Clone().Parent = game.Workspace end
this wouldn’t work, I don’t know how the built-in method does it, but it’s part of the issue
I am glad, that the Engine doesn’t break ObjectValue’s for StarterGui, but only if it’s contained inside a container.
Basically, things get cloned, but for things outside of containers, they do get cloned, but they won’t reconnect their cloned things. This is a very slight issue. But it should emphasize what I am trying to say with, how the Engine can copy things and re-connect them, and how developers can’t do that without actually implementing logic, while the Engine has it.
ObjectValue
a Instance that holds another Instance as a Value. Very useful to link things together. Designed to be simple bridges in Scripts. But simplicity breaks, because there’s complexity that ObjectValue Instances were not prepared for.
It has problems.
Problems that I’d not like to solve with something like this
while (ObjectValue.Value == nil) do
task.wait()
end
This above code, works. but… I don’t like it.
I don’t want a ModuleScript Handler for one thing. I like C++ implementations. They’re faster, they’re built-in, they’re supported.
I am looking at a ObjectValue
something designed to hold values. But currently it’s nothing but something like all the other Value Instances. Something that is just Value
. This does not work for Instances. Instances need a help-care support to work with ObjectValue’s, which is not available.
Problems that can’t be solved with .Changed
because if the Instance already exists it won’t trigger Changed
. And Changed
seems to listen for Changes for the referent. There used to be a bug report about moving things from Client to Server, not triggering Changed or something, or destroying the instance. That’s normal. If you want to change the ObjectValue’s Value. Change the Value
.
We are talking about something that you can’t see, which seems to be referred to as RefPropDescriptor
, the referent
value.
The referent
value seems to be an Instance’s ID, used for Replication across Server and Client.
When you assign something, this is how it looks like
<Item class="ObjectValue" referent="RBXF35BF9CC7CB04266BBCE5BB07A6CA382">
<Properties>
<BinaryString name="AttributesSerialize"></BinaryString>
<SecurityCapabilities name="Capabilities">0</SecurityCapabilities>
<bool name="DefinesCapabilities">false</bool>
<UniqueId name="HistoryId">00000000000000000000000000000000</UniqueId>
<string name="Name">Value</string>
<int64 name="SourceAssetId">-1</int64>
<BinaryString name="Tags"></BinaryString>
<UniqueId name="UniqueId">1672313e268e785a06b1e17200004812</UniqueId>
<Ref name="Value">RBXB41D84CE01954EB88936335940F57DF8</Ref>
</Properties>
</Item>
The issue
-
Value
always returnsnil
, this is fine.- What’s not fine is that there’s nothing else.
- You’re unable to check if an
ObjectValue
is bound to something.- In this case I bound an ObjectValue to a server-side Object. As it is a permanent way to demonstrate the issue.
Further issues occur internally on Roblox.
The AccessoryDescription
holds a value called Instance
, which is linked to a Instance (a referent). It is going to have the same issues, just like ObjectValue. And it’s a question whether Roblox themselves is having repetitive code for that in their Engine.
I can’t verify whether ObjectValue
is reliable for all cases, the Engine seems to pause things when someone alt-tabs or something.
Re-production Steps
ObjectValue_test.rbxlx (75.4 KB)
- Run the game
-
nil
is being printed - Comment out the while loop
-
nil
won’t be printed anymore, it will printTextLabel
- You have just witnessed a Luau workaround for this issue.
This is expected. This is not a bug. But this is the demonstration of the issue. Since, the ObjectValue is put inside ReplicatedFirst
it’s replicated first! Before anything else.
Expected Result
Built-in implementations that make ObjectValue more robust against performance and replication cases.
Currently, you can compare ObjectValue to a Symbolic Link Folder on Windows, without a :WaitForChild
feature.
Actual Result
- You can’t check whether a ObjectValue is actually bound to something or not, in its
Value
Property. EVEN Though the Reflection has information for it. - There’s no built-in implementation to
WaitForInstance
(Only if it’s bound to something)
And due to that, it’s not a simple bridge anymore.
Additional notes.
I had the idea that ObjectValue’s could only be created if their Value exists. Don’t actually do that. I believe it’s an awful design. And it won’t work with AccessoryDescription either.
There’s no Attribute for Instances. I don’t see the issue why there can’t be one. But there is an issue for implementing one. Since the ReflectionMetadata would call this type of Attribute an Instance
, it would not expose extra methods…
Perhaps there will have to be a new type of thing called InstanceRef
, a property that holds a reference to an Instance, with designed methods to retrieve the Instance if it is available. (This is sorta reflecting me back to ObjectValue)