As a Roblox developer, it is currently difficult to tell whether or not something is a value object. Value objects such as “StringValue” do not inherit from a base class. This means to tell if something is a value object you either have to check the class name for each value object type, or check in a pcall if the Value property exists on the object (which can be unreliable).
local function IsValueObject(Obj)
return Obj.ClassName:match('Value$') ~= nil;
end;
This also works. I agree there is a need for a base class, but it can be currently solved in this way, and it’s easy enough that it makes the need for it just a small quality of life improvement.
The dictionary lookup is fastest. I find the pattern matching easiest to remember and write, but it’s the slowest. The substring is a reasonable string manipulation approach without using overkill patterns, but it’s not as fast as the lookup. :find is slightly faster than using :sub, but it doesn’t beat the dictionary lookup.
I tested it multiple times and the results were consistent.
Code
local isValueObjTable = {
BrickColorValue = true,
CFrameValue = true,
ObjectValue = true,
IntValue = true,
NumberValue = true,
Vector3Value = true,
RayValue = true,
StringValue = true,
Color3Value = true,
BoolValue = true,
}
local function method1(instance)
return isValueObjTable[instance.ClassName] ~= nil
end
local function method2(Obj)
return Obj.ClassName:match('Value$') ~= nil
end
local function method3(v)
return v.ClassName:sub(-5) == "Value"
end
local function method4(v)
return v.ClassName:find("Value", 4, true) ~= nil
end
local value = script.Value
local function benchmark(func, name)
local begin = tick()
for i = 1, 10000000 do
func(value)
end
local elapsed = tick() - begin
print(name..": "..elapsed)
end
benchmark(method1, " Lookup")
benchmark(method2, " Patterns")
benchmark(method3, "Substring")
benchmark(method4, " Find")
All 5 feature request threads about this have involved a benchmark of sub/find/match, which is actually pretty impressive from a consistency standpoint.