The Problem
The current design of the CollectionService’s Tag API is a bit verbose when it comes to applying tags.
Consider the following example:
if not CollectionService:HasTag(instance, "SomeTagName") then
CollectionService:AddTag(instance, "SomeTagName")
end
for _,tag in pairs(CollectionService:GetTags(instance)) do
print(tag)
end
if CollectionService:HasTag(instance, "SomeTagName") then
CollectionService:RemoveTag(instance, "SomeTagName")
end
As you can see, CollectionService
is kind of awkwardly wedged into every single query and operation here, when ultimately its just wrapping around one instance in this context.
Proposed Solution
To make things less verbose and cleaner to read, it would be handy if the APIs were instead part of the Instance class itself:
if not instance:HasTag("SomeTag") then
instance:AddTag("SomeTag")
end
for _,tag in pairs(instance:GetTags()) do
print(tag)
end
if instance:HasTag("SomeTag") then
instance:RemoveTag("SomeTag")
end
Backwards Compatibility Rationale
This change can be made without disrupting the existing API. Although its not a common practice, it is possible for API members on Roblox to “override” a member of its base classes.
Some examples of this include:
Function void Model:BreakJoints() [Virtual]
Function void Workspace:BreakJoints(Objects objects) {PluginSecurity} [Override]
The Workspace class is a model, and Workspace:BreakJoints
overrides Model:BreakJoints
Event Instance.Changed(string property) [Virtual]
Event ValueBase.Changed(Variant value) [Override]
Each Changed
event defined in the derived classes of ValueBase
override Instance.Changed
.
In practice, we would see the following “override” behavior introduced with this API change:
Function void Instance:AddTag(string tag) [Virtual]
Function void CollectionService:AddTag(Instance instance, string tag) [Override]
Function Array Instance:GetTags() [Virtual]
Function Array CollectionService:GetTags(Instance instance) [Override]
Function bool Instance:HasTag(string tag) [Virtual]
Function bool CollectionService:HasTag(Instance instance, string tag) [Override]
Function void Instance:RemoveTag(string tag) [Virtual]
Function void CollectionService:RemoveTag(Instance instance, string tag) [Override]
The tag functions that exist under the CollectionService would remain and override the new functions. As a side effect, managing tags on the CollectionService object itself would require you to pass it as an argument to these functions:
CollectionService:AddTag(CollectionService, "Tag")
CollectionService:RemoveTag(CollectionService, "Tag")
But this is what would be done anyway if people are (for whatever reason) adding tags to the CollectionService today, so this isn’t a breaking change.
Function Objects CollectionService:GetTagged(string tag)
Function RBXScriptSignal CollectionService:GetInstanceAddedSignal(string tag)
Function RBXScriptSignal CollectionService:GetInstanceRemovedSignal(string tag)
The CollectionService would still serve as a hub for querying objects that have a tag as well as listening for when tags are added and removed. It would just be more compact to read and write code for managing an individual object’s tags.
I hope this change will be considered. Thank you for reading!