.Changed should not fire for properties that aren't Lua-scriptable

User Story:

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.

Relevant bug reports:
https://devforum.roblox.com/t/weird-vehicleseat-error/52711/

Expected Behavior:

If a property is not Lua-scriptable it shouldn’t fire Changed.

Further Notes:

Ignore most of the replies below. There was a misunderstanding in original terminology.

12 Likes

I disagree with your argument.

  1. 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.
  2. 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
  3. 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.

7 Likes

It’s being used in a plugin – FE does not apply.

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. :slightly_smiling:

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). :slightly_smiling:

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.

:slightly_smiling:

edit: formatting

2 Likes

Plugin source: Plugin Source - Pastebin.com
Offending code:

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.

3 Likes

Ah. A much better reproduction of one line of code.

> game.StarterGui.ScreenGui.Changed:connect(function(Prop) print(Prop) end)
ReplicatingAbsoluteSize
AbsoluteSize
ReplicatingAbsoluteSize
AbsoluteSize
ReplicatingAbsoluteSize
AbsoluteSize
ReplicatingAbsoluteSize
AbsoluteSize
ReplicatingAbsoluteSize
AbsoluteSize
ReplicatingAbsoluteSize
AbsoluteSize
ReplicatingAbsoluteSize
AbsoluteSize
ReplicatingAbsoluteSize
AbsoluteSize

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.

1 Like

I just wish non-queryable properties would throw a warning and return nil if you try to read it/do nothing if you try to write to it.

It seems kinda dumb that I have to manually filter out properties to make sure it doesn’t error.

1 Like

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.

1 Like

If you use the API dump, you won’t even know of those properties.
(Actually, aren’t there a few listed on the AD that aren’t scriptable? I forgot)

I would appreciate it if this were added. Posting in regards to Weird VehicleSeat error - #7 by EchoReaper

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)

I’m using it to handle Throttle and Steer and inside of my function I check if the property is equal to those.

Read the value after you determine the property name, not before.
Alternatively, consider using GetPropertyChangedSignal.

1 Like

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.

6 Likes

It’s taunting us with “This property exists, and you know it even changes, but you can’t touch this!”

2 Likes

A post was merged into an existing topic: Memes, Puns & Meme related GIFs Thread