Built-In RbxUtility.Create

LoadLibrary has been deprecated. While a lot of the functionality in those modules are obsolete due to changes in features, RbxUtility.Create remains exceedingly useful. To follow best practices, how should we continue using Create? Have everyone who uses it individually copy+paste it into a unique model in all of their projects that use it? That’s a huge mess.

It’d be great if this common behavior was built into Instance.new and a table could optionally be provided as the third parameter so Instance.new("Part", workspace) would keep current behavior, but:

Instance.new("Part", workspace, {
    Size = Vector3.new(2,2,2);
    Color = Color3.new(1,0,0);
})

Would create a part, set its properties, and then parent it to Workspace. Parenting should always occur last as setting properties after Parent can cause performance issues.

27 Likes

Would it not be more convenient if parent was kept separate in the API, i.e:

Instance.new("Part", workspace, { ... })

Then it is more clear that it is a special property in the bunch (it is applied last always, which is not clear if it’s in the table) and it also looks cleaner to me since it just adds an argument rather than changing the type of the second argument into a Variant

6 Likes

Yeah, that’s probably a good idea. Updated OP.

1 Like

How should Instance.new proceed when it encounters an error while processing a property (e.g. incorrect type)? What if multiple properties have errors?

Ideally it should be the same error as if the property were being set manually. For instance,

local part = Instance.new("Part", workspace, {
    BrickColor = false;
})

would spit out an error Attempt to set BrickColor to boolean; expected BrickColor; line 3. If there are multiple errors, ROBLOX would just break at the first error, and the subsequent ones wouldn’t be encountered. The developer would encounter and fix them one by one, which I don’t think is unreasonable given that’s how it would happen if done manually:

part.BrickColor = false
part.CustomPhysicalProperties = -1

This would first error on the BrickColor setting and not continue executing to find the next error. The next error would only be found after the first has been fixed.

1 Like

I don’t see a problem with this. I’ll propose it internally if someone hasn’t beat me to it.

6 Likes

Note that the line with the offending property can’t actually be determined. Regardless, the name should be enough to point the user in the right direction.

Also, it might be worth having the table sorted in some way, in the interest of keeping things deterministic.

1 Like

Keep in mind that this method has actually never necessarily been best practice. The main problem with this methodology is that because you’re using a dictionary (which is a hash table internally), you can’t know what properties are going to be assigned first. It’s usable in a lot of cases, but over-reliance will potentially come back to bite you in the rear. Caution is advised. Alternatively, the API could look more like this:

Instance.new("Part", workspace, { "BrickColor", BrickColor.new("Really red"), "Size", Vector3.new(1, 1, 1), "TopSurface", "Smooth", "BottomSurface", "Smooth", "Anchored", true, "CanCollide", false })

It’s admittedly annoying to type quotes around every property name but in this case at least order is guaranteed.

The problem you have there is that the user may not even know they need to set the properties in a specific order. I’ve spent up to half an hour helping newbies debug only to find because Size was set after CFrame, the part was being adjusted 50 studs in the air.

I don’t think the solution is to control the order of property setting, but to alleviate the issue that, to the user, order matters in the first place. This could be done by specifying any necessary orders in ReflectionMetadata/etc and having a list of properties like this set them in that order.

Alternatively, we can control the order and target sane behavior if we go with this. It’s trivial to order the property names once they’re in C++. You almost never want to set Size after CFrame if you’re creating parts this way. If you wanted that behavior, you could pull it out yourself.

1 Like

Size vs CFrame wouldn’t be a problem, since the behavior only happens when the part is in the workspace.

There are still a few case where it is a problem, though. One example I can think of is GuiObject.Transparency vs BackgroundTransparency/TextTransparency.

Well for that example in particular, GuiObject.Transparency is technically deprecated, so I don’t think it’ll be that much of an issue.

3 Likes

I think the API should look like:

Instance.new("Part", workspace, "Size", Vector3.new(2,2,2), "Color", Color3.new(1,0,0))

Because having to create temporary tables on the fly just adds more work to the garbage collector.