Allow :Clone() to take table argument w/ object properties

Currently, the :Clone() method doesn’t take any arguments and simply returns an exact copy of the instance that was cloned. Usually, though, people using this function will end up wanting to change a few of the properties of the cloned instance. To do this, they end up defining the cloned object as a variable and then make multiple lines of code editing the object’s property.

I think it’d be awesome if we could simply pass a table as an argument which contains property data. This would work exactly like TweenService’s PropertiesToTween table it allows to be passed.

Long story short,
This:

local newPart = workspace.Part:Clone()
newPart.Parent = workspace
newPart.BrickColor = BrickColor.Random()
newPart.Position = Vector3.new(1,2,3)

Would now look like this:

workspace.Part:Clone({Parent = workspace, BrickColor = BrickColor.Random(), Position = Vector3.new(1,2,3)})

(The method will still, of course, return the new cloned part)

I think this is a much cleaner and more optimal method of setting properties to a cloned object. I cannot currently think of any downsides to this, but if anyone does, let me know.

11 Likes

What if we were to clone a model with many instances? Then it would get complicated. The current method doesn’t hurt performance.

1 Like

As useful as this may be, couldn’t you just create a short function to do this process?

Pretty much:

local function CloneAndApply(Object, Dictionary)
    local Clone = Object:Clone();
    
    for Name, Value in pairs(Dictionary) do
        Clone[Name] = Value;
    end

    return Clone;
end

Would something this simple really need to be added?

3 Likes

That is a good point. In that case, the dictionary could still function as intended, but simply for the limited number of properties that a “Model” has.

Just because something is simple doesn’t mean it isn’t worth being added. Tons of functions and methods in Roblox are simply things that could’ve otherwise been written as functions the way that you did in your reply, but Roblox of course values ease and a streamlined experience when using studio. Heck, you could even define your own function for the entire :Clone() method pretty easily. The point of the suggestion is to make scripting in studio more optimal and smooth.

This does not work due to the fact that Lua tables are not ordered yet the order of property assignment does matter.

In this case you’re using the table argument as a hashmap. As you add more properties to the hash map, what “order” (if you iterated over them) they’ll show up in the hash map in will change pseudo-randomly as you add more properties. That’s a problem for this API design because there’s quite a few cases where the order in which properties are assigned to an Instance matters.

I don’t think there’s any way to salvage this design. Having to construct some kind of array of (prop, value) pairs to pass instead would make this awkward enough that it probably wouldn’t get much use.

3 Likes

Also the :Clone() method is meant to return an exact copy of the instance and modifying it kinda ruins the purpose of it. I do think it is kinda a pain to have to edit clones manually but I don’t mind it because that is the purpose of the :Clone method.

This is for Parent and for min/max-paired / constraints-correlated properties, right?

I think you have a point, but if the engine had this and deprioritized Parent, that would probably already cover 99.9% of use cases for this.

2 Likes

That works fine for now, but if in the future we add more properties where order does matter that’s more special cases that have to be added to this, and which someone can forget to add causing rare weird unpredictable behavior. Using special cases to fix it would be trying to work around a fundamental flaw with design, which is not sustainable.

There’s also a secondary problem with this API, which is that it’s very easy to incorrectly use this API. Case and point, this very post which is suggesting the API uses it incorrectly:

workspace.Part:Clone({Parent = workspace, BrickColor = BrickColor.Random(), Position = Vector3.new(1,2,3)})

That’s not the correct way to use this, you should be doing this:

local FOOBAR_PROPS = {Parent = workspace, BrickColor = BrickColor.Random(), Position = Vector3.new(1,2,3)}
...
workspace.Part:Clone(FOOBAR_PROPS)

That is, reusing the same props table for every call to clone. Yet the way the API is structured encourages you to make a new table every time you want to do the clone call, which hurts performance compared to what you would have done otherwise.

1 Like