Can we detect what type a variable is?

I am trying to make this little thing that helps me create ValueObjects by sending the arguments into a function like this:

function VObject.new(type,parent,name,value)
    if type = "int" then
        -- make an IntValue
    elseif type = "bool" then
        -- make a BoolValue
    elseif type = "string" then
        -- make a string value
    end
end

As you can see, I have it set up to accept “type” as an argument and then a few ifs to see what type of ValueObject to create. I was wondering if can simplify this and just detect what the variable is from the value argument but I just haven’t found a way to do this.

Is there any way to detect the type of a variable?

Thanks!

8 Likes

Quoting from https://developer.roblox.com/api-reference/lua-docs/Lua-Globals:

string type ( Variant v )
Returns the type of its only argument, coded as a string. The possible results of this function are “nil” (a string, not the value nil), “number”, “string”, “boolean”, “table”, “function”, “thread”, and “userdata”.

7 Likes

There are no different number datatypes in Lua: 1.2 and 1 for example are just “number” and not int or float or double.

The datatype for booleans is boolean, not bool.

Also side note: that is not getting the type of the variable itself. It is what is contains.

1 Like

You may have better interest in typeof() as it is more verbose regarding certain types in Roblox specifically, e.g. passing in an instance into type will return userdata whereas passing it into typeof will return Instance. This is the same for other objects e.g. Vector3, CFrame, etc.

24 Likes

so does that mean we should always use typeof() as a full replacement of type() in all cases?

1 Like

I do so personally, as typeof() includes all of the stock return data of type()

6 Likes
local OBJECT_NAME_FORMAT = "%sValue"

local function ValueObject.new(Type, Parent, Name, Value)
    local success, object = pcall(Instance.new, OBJECT_NAME_FORMAT:format(Type))
    if success and object then
        object.Name = Name
        object.Value = Value
        object.Parent = Value
        return object
    else
        error(object)
    end
    return nil
end

I feel filthy for spoonfeeding, but I feel like it’d never be brought to light if I didn’t. Try using this code. It’s actually pretty neat. Instead of trying to detect the type of the variable, perhaps change up your function itself a little. What it does:

  • Accepts four parameters; Type, Parent, Name and Value
  • Contains a format for the name; Type parameter will be pushed to the %s part of the name format
  • Wraps Instance.new in a protected call and passes the formatted name to Instance.new
  • If success is true, there should be an object returned - we set the properties and then send it off, while returning this object in case a variable needs to reference it
  • If success is false, that means Instance.new failed to create the instance and we need to throw an error

Modification is in your hands, or you can salvage this code into something of your own. Not sure if this accomplishes what you want though, since this doesn’t create a ValueObject based on a variable’s type. I just simplified the function.

That being said, you could also evaluate a single line to get a “type” and combine it with the above.

local SomeVariable = "A"

-- elsewhere

local TypeForVariable = type(SomeVariable) -- Don't need Roblox classes, forget typeof()
local ClassPrefix = (TypeForVariable == "boolean" and "Bool" or whatever and something)
3 Likes

To add on to your solution, I think using dictionary would be a lot easier.

local datatypePrefixes = {
    boolean = "Bool",
    string = "String",
    number = "Number"
};

And you would index the table like this

datatypePrefixes[type(argument)]

Creating an instance

local valueBase = Instance.new(datatypePrefixes[type(argument)] .. "Value");
1 Like

Forgot about the whole dictionary thing. :stuck_out_tongue: I’m so used to condition and result or condition2 and result2. Won’t bother editing my post, but that would definitely be a burden off the shoulders to use a dictionary over a long evaluation statement.

your code sample say to forget typeof() and you dont need Roblox classes, why is that?

You’re only attempting to create ValueObjects based on the type of value that a variable is holding, no? In that case, you wouldn’t need to reference Roblox classes like Instance unless you’re using some of the more uncommonly used value objects such as Vector3Value or whatnot.

If your function is supposed to account for all ValueObject types existing, then forget that - typeof would be a good function to use. type() would just give you “userdata” for objects.

1 Like

I appreciate all the input here. Some of it seems a bit more verbose than is needed for this little function, but again, I SUPER APPRECIATE the input and I learned a bunch!

This is what I have written so far:

function VObject.new(name,value,parent)
    local NewValue
    if type(value) == "number" then
        NewValue = Instance.new("NumberValue")
    elseif type(value) == "boolean" then
        NewValue = Instance.new("BoolValue")
    elseif type(value) == "string" then
        NewValue = Instance.new("StringValue")
    end
    NewValue.Name = name
    newValue.Value = value
    NewValue.Parent = parent
end

Thanks!

4 Likes

“typeof()” does seem to be a split second faster for me instead of “type()” since it is specified for Roblox Lua. But it’s just like millisecond difference.

No, type is faster than typeof.
Screen Shot 2021-06-04 at 5.01.08 PM

local init1s = {} 
local init2s = {} 
local types = {
	'str';
	1;
	{};
}
local typeofs = {
	Vector3.new();
	CFrame.new();
	'str';
	1;
	{};
	Color3.new();
}
for i = 1,1000 do 
	local init = tick() 
	for i = 1,1000 do
		type(types[i % 3])
	end
	local init1 = tick() - init 
	init1s[#init1s + 1] = init1 
end 
wait(5)
for i = 1,1000 do 
	local init = tick() 
	for i = 1,1000 do
		typeof(typeofs[i % #typeofs]) 
	end
	local init2 = tick() - init 
	init2s[#init2s + 1] = init2 end 
local 
total1s = 0 
for i,v in pairs(init1s) do 
	total1s += v
end 
local avg1s = total1s / 1000 
local total2s = 0 
for i,v in pairs(init2s) do 
	total2s += v 
end 
local avg2s = total2s / 100000 
print('Average type()', avg1s) 
print('Average typeof()',avg2s)
1 Like

Oh shoot! Thanks for letting me know! Hm I just used prints in 2 separate scripts and I saw typeof always on top.

But man your calculations seem correct cuz I don’t understand any of that. xD

Edit:

Ah actually
“Typeof()” takes the crown. 10 to the power of -7 or e -7 is smaller making it microdecimals faster.

Must’ve got confused there 7z99. Cool calculations though :sunglasses:

3 Likes

No, type isn’t faster than typeof just because of a negligible performance difference.

1e-07 is smaller (faster) than 1e-05

indeed! ae±b represents a * 10^(±b).
so 1e-07 represents 1 * 10^-7 which is equivalent to 1 * (1 / 10^7)

2 Likes

this is a very very old post, im sorry for bumping

you are right, but in his calculations, didn’t you notice he did this?

local avg1s = total1s / 1000
...
local avg2s = total2s / 100000

that means type() is actually 1.32e-7 which is faster
anyways there is almost no difference even when i tested this same code

1 Like
local valueObject = {}

valueObject.types = {["string"] = "String", ["number"] = "Number", ["boolean"] = "Bool"}

function valueObject.new(name, value, parent)
	local valueType = valueObject.types[type(value)]
	if valueType then
		local newValue = Instance.new(valueType.."Value")
		newValue.Name = name
		newValue.Value = value
		newValue.Parent = parent
		return newValue
	end
end

valueObject.new("Pi", math.pi, workspace)

return valueObject
1 Like