Client Difference Log
API Changes
Added Property string BasePart.MaterialVariant [NotReplicated]
Added Property Font TextBox.FontFace
Added Property Font TextButton.FontFace
Added Property Font TextLabel.FontFace
Added Function void LSPService:RegisterLSPCallback(Enum.LSPMethodType methodToOverride, Function callbackFunction) {RobloxScriptSecurity}
Added Function Dictionary TextService:GetFamilyInfoAsync(Content assetId) [Yields]
Added Enum LSPMethodType
Added EnumItem LSPMethodType.Initialize : 1
Added EnumItem LSPMethodType.Initialized : 2
Added EnumItem LSPMethodType.CancelRequest : 3
Added EnumItem LSPMethodType.TextDocument_didOpen : 4
Added EnumItem LSPMethodType.TextDocument_didChange : 5
Added EnumItem LSPMethodType.TextDocument_didClose : 6
Added EnumItem LSPMethodType.TextDocument_foldingRange : 7
Added EnumItem LSPMethodType.TextDocument_onTypeFormatting : 8
Added EnumItem LSPMethodType.TextDocument_formatting : 9
Added EnumItem LSPMethodType.TextDocument_rangeFormatting : 10
Added EnumItem LSPMethodType.TextDocument_hover : 11
Added EnumItem LSPMethodType.TextDocument_signatureHelp : 12
Added EnumItem LSPMethodType.Workspace_DidChangeConfiguration : 13
Added EnumItem LSPMethodType.ShutdownRequest : 14
Added EnumItem LSPMethodType.Completion : 15
Added EnumItem LSPMethodType.Declaration : 16
Added EnumItem LSPMethodType.DocumentSymbols : 17
Added EnumItem LSPMethodType.TextDocument_publishDiagnostics : 18
Added EnumItem LSPMethodType.Window_showMessage : 19
Added EnumItem LSPMethodType.Window_showMessageRequest : 20
Added EnumItem LSPMethodType.Roblox_registerSyntaxCategories : 21
Added EnumItem LSPMethodType.Roblox_signalQuiescence : 22
Added EnumItem LSPMethodType.Roblox_syntaxHighlight : 23
Added EnumItem LSPMethodType.Roblox_suggestExtraSelections : 24
Added EnumItem LSPMethodType.Roblox_findExecutablePosition : 25
Added EnumItem LSPMethodType.Roblox_findColor3 : 26
Added EnumItem Font.Unknown : 100
Removed Enum PacketPriority
Removed EnumItem PacketPriority.IMMEDIATE_PRIORITY
Removed EnumItem PacketPriority.HIGH_PRIORITY
Removed EnumItem PacketPriority.MEDIUM_PRIORITY
Removed EnumItem PacketPriority.LOW_PRIORITY
(Click here for a syntax highlighted version!)
Whoot! What an addition to UI customisability. I’m curious to see how this will be implemented; how will it affect game-loading times and how failures to load will be dealt with.
Does this mean that asset permissions are automatically edited when manually adding a sound? This sounds like something I’d like to be notified about.
Well… now you’re just pampering me.
Would this be the same as this generic function I did?
function Module.TableCopy(Original) -- physical table duplication
local Copy = {}
if Original then -- if the source table came void, return {}
for k, v in pairs(Original) do
if type(v) == "table" then
v = Module.TableCopy(v)
end
Copy[k] = v
end
end
return Copy
end
Different in a couple of ways:
-
table.clone
is a shallow copy that doesn’t copy sub-tables, so remove the recursion. -
It also copies the metatable if it exists, so you’d have to add a
getmetatable
/setmetatable
pair in yours.
Also it’s not so much that the function is hard to write, but that it’s so ubiquitous that it makes sense to include in the standard library.
You just identified some of the very reasons it took so long to for this to arrive as a feature! It’s quite an interesting system and all of those things were accounted for.
Looking at the RFC, table.clone recreates the structure of the table internally and takes a lot less time over using Lua, since you’re not constantly resizing the table, and the memory is preallocated for the table.
Bearing in mind that a table can always have sub-tables, why create a new instruction that could cause confusion if used by someone who wants to clone a table with multiple levels?
Perhaps table.clone could be made to have a feature similar to FindFirstChild where the second argument, a boolean, is used to force recursive.
Basically: local tableClone = table.clone(tableToClone, true)
Generally shallow copy is more likely to be what you wanted. Imagine I have the following:
local customPlayerObject = MyLuaPlayer.new(...)
local players = {table of these}
table.clone(players) --> Probably 💣💥 if it did a deep copy
Basically the issue is that deep-copy is dumb and doesn’t know “where to stop”, that is, what the “atomic” copy-by-reference parts of your data structure are intended to be because everything in Lua is just tables.
Even if you’re writing functional style code, more likely than not what you want is a shallow-copy of your top-level data structure which keeps references to the same immutable contents as the original but changes one or a couple of fields of the toplevel structure.
Deep-copy is a construct which is absolutely filled with perils, and it’s better to keep it locked away behind you having to implement it yourself IMO. table.clone
allows you to easily make an efficient implementation of deep-copy now if you so desire though.
Are there plans to add a metamethod, eg __type
to allow developers to return a custom string when typeof()
is called on a table with the __type
metamethod? Right now I have to differentiate between tables and lua objects by checking if Object._IsObject == true
Additionally, with deep cloning it’s unclear what “clone” means for many things. Does it apply to instances? What about things like CFrames that you can’t clone? What about threads? Etc. These are all things that you as a developer sort of have to decide or implement, and, deep clone would just be confusing if implemented in the engine I think.
Even assuming you just restricted it to other tables, it would not really fit as a feature imo, and it’d be a lot more difficult to implement in the engine than in lua, especially because you can also implement this kind of deep cloning with the same shallow cloning behaviour pretty easily like this:
local function deepclone(data)
local clone = table.clone(data)
for index, value in pairs(clone) do
if typeof(value) == "table" then
clone[index] = deepclone(value)
end
end
return clone
end
Note that this doesn’t take care of what happens if you have a circular table (E.g. a table that eventually has itself contained). Here’s a less clear version which fixes this, and also clones metatables:
local function deepclone(data, clones)
clones = clones or {} -- A set of tables which are being cloned already in this call, so we can avoid cloning circular tables. When there's a circular table it gets kept without being cloned, but you also might not want this
clones[data] = true
local clone = table.clone(data)
-- Clone metatable
local meta = getmetatable(clone)
if meta then
setmetatable(clone, deepclone(meta))
end
for index, value in pairs(clone) do
-- Clone, but only if not already being cloned
if typeof(value) == "table" and not clones[value] then
clone[index] = deepclone(value, clones)
end
end
clones[data] = nil
return clone
end
There is a feature request.
I doubt it, and, it is something that I no longer really think is a particularly good idea. I think I might’ve asked something similar a while back, and, it sort of just presents many issues. My sole use case from what I can remember was being able to effectively spoof other data types in a sandboxing environment, but, I can just do this by replacing the behaviour of typeof
in managed code.
The problem is that it sort of just complicates something that doesn’t need to be complicated, and it solves a problem that doesn’t need to be solved if you manage all of the code in your game, because, well, you can just replace your typeof
behaviour yourself. Albeit, this might not be ideal, but, it is still better than using a metamethod for it imo.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.