As a developer, Changed is not reliable enough because it can break my code by firing for properties that are not Lua-scriptable. For instance: ReplicatingAbsoluteSize.
Example of Broken Code:
local propertyValues = {}
screenGui.Changed:connect(function(property)
propertyValues[property] = screenGui[property] --Errors because ReplicatingAbsoluteSize is not Lua-scriptable and cannot be read
end)
Improvements to Development Experience:
Should this issue be resolved, my development experience would be improved by not needing to manually blacklist certain events from Changed, and not needing to worry about my code breaking whenever a non Lua-scriptable property is added in the future.
AbsoluteValue is readable and a useful property to read.
Example usage: Expecting .Changed for AbsoluteSize to fire is needed when we want to know when someone resizes their screen.
AbsoluteValue isn’t settable, that is true, but you never said that. You said it’s not queryable (that is, readable). I guess it’s just a typo.
The example use, (replicating any property on .Changed), is a bad practice.
Using FilteringEnabled and then replicating changes on the .Changed by passing to a RemoteEvent is both inefficient and defeats the purpose of using FilteringEnabled.
This results in blindly replicate changes, but RemoteEvents are more expensive than using ROBLOX’s native replication
Yes, you can start filtering properties and things with your suggested replicated system, but then you’re defeating your original purpose of having .Changed fire for only queryable properties.
Using pcall to solve this is also incrediably inefficient
The property argument in the .Changed is there to help you filter out changes that you don’t want. Use it!
My suggestion is to start using FilteringEnabled correctly, or not at all.
Until I actually see proof of a property that cannot be read or written (i.e. errors on read), that fires .Changed, I vote against this feature.
The plugin it’s being used in is a CoreGui two-way mirror since ROBLOX broke showing the contents of the actual CoreGui in the explorer when it was force-enabled through the reflectionmetadata.xml. If you change one thing in the dummy CoreGui or a CoreScript changes something in the real CoreGui, the property changes need to replicate to the same object on the other side of the mirror – there’s no way around that.
It’s not a typo. ReplicatingAbsoluteSize is an actual property that’s not the same as AbsoluteSize. It can’t be read (if you do print(screengui.ReplicatingAbsoluteSize) you get an error).
This is not a feature request to stop firing for read-only properties. It’s a request to stop firing for properties that can’t even be read.
There isn’t a convenient list of non-queryable properties to blacklist – they’re not on the wiki page nor in the API dump. You happen upon them by chance, and that’s not a good thing to have to work with. Even if there was a list of them, why are we having to deal with non-usable properties?
omg noob it’s not an argument. Jumping into stuff in the mindset that it’s a win/lose battle is a no no – can’t we just have a productive and friendly conversation?
Let’s start with this. I said I disagree with your argument because I wanted to avoid the ad-hominem attacks that seem to get thrown around in forums. It’s not about winning an argument, it’s about respectfully discussing this sort of thing.
I agree we should do that, and that’s why I opened with that. Let me reword: I disagree with your argument for “.Changed should not fire for non-queryable properties” which is what we were discussing.
I’m sorry if I somehow came off as attacking you. I merely intended to attack your argument (which is why that was first specified).
Yep. You get an error saying it doesn’t exist.
> print(game.StarterGui.Frame.ReplicatingAbsoluteSize)
21:06:06.153 - ReplicatingAbsoluteSize is not a valid member of Frame
21:06:06.156 - Script 'print(game.StarterGui.Frame.ReplicatingAbsoluteSize)', Line 1
21:06:06.157 - Stack End
> game.StarterGui.ScreenGui.Frame.Changed:connect(function(Property) print(Property) end)
Size
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
AbsoluteSize
I stand by initial argument, even with the new information, as I can’t reproduce the error. Of course, I haven’t put a lot of effort into this, but a copy of your plugin that repros it will work fine.
syncConnections[object] = object.Changed:connect(function(property)
modifyProperty(clone, property, object[property])--trying to index object[property]
end)
Repro video:
Edit: ReplicatingAbsoluteSize is a member of ScreenGui – not Frame. That’s why you weren’t getting the correct error.
“Non-scriptable” or “unstable” is the generally accepted term when referring to these kinds of properties. I assume that’s what you mean.
I brought up this exact issue years ago when they were making changes involving these properties. I thought I remembered someone saying that it was going to be fixed, but it never happened.
First of all, neither one of those are settable, so using .Changed to modify won’t work out anyway. In any event, it looks like it fires double because the replicating part fires.
I’d still not recommend syncing the way you’re doing, but arguable that single property shouldn’t trigger a .Changed event.
Being settable has nothing to do with it. ReplicatingAbsoluteSize cannot be queried. Unlike AbsoluteSize which can be read, print(screengui.ReplicatingAbsoluteSize) will error with “Unable to query property ReplicatingAbsoluteSize. It is not scriptable.” ReplicatingAbsoluteSize cannot be used at all.
There are more (i.e. DraggingV1 of BasePart) – it’s not just ReplicatingAbsoluteSize. Regardless of the number though, these properties should not trigger .Changed. They are of no relevance to and can’t be used by us – the only thing they accomplish is causing errors. Of course they shouldn’t fire .Changed.
There is no other way. No matter how you go about it, syncing two parts’ properties is setting the opposite one’s property to the value of the changed one.
That feels like the wrong word to use… maybe ‘read’ works better
That aside, I totally agree that a property shouldn’t fire changed if it can’t even be read. Maybe making it readable is a solution or the other solution is removing the changed signal.
Why not just listen to the specific properties you’d like to change?
It’s a bad idea to simply query a property if you don’t know what property you’re accessing.
Regardless of what we think best practices are, unless Changed is deprecated, ROBLOX is encouraging developers to use it. Since it’s intended to be used, it shouldn’t cause unexpected errors. There are also use cases for listening to every property (e.g. mirroring an instance, only subscribing to a single event instead of 20 if a large number of properties need to be subscribed to, etc)
This is a bug I’d like to fix, but it’s a dangerous change internally. I’ll try to see if I can do it. There’s no reason for us to expose unscriptable properties in our API. It should be as though they don’t exist.