Can someone explain this Luau error for me?

I am trying to figure out how to use this Luau type-checking stuff, and I’m experimenting with some basic functions to start with. In this example, I want to have a function convert a given array’s values from instances to their names.

local function Array_InstanceToString(Array)
	for i = 1, #Array do
		Array[i] = Array[i].Name
	end
	return Array
end

Pretty simple. Now here’s Roblox’s guideline on setting up type-checking for functions, specifically for the input and return tuples, retrieved from here.

Function types are specified using the arguments and return types, separated with ->
local foo: (number, string) -> boolean

On the same page, they specify that arrays in particular have their own shorthand syntax:

When the table consists of values keyed by numbers, it’s called an array-like table and has a special short-hand syntax, {T} (e.g. {string} ).

Here is my attempt at following that guideline.

local Array_InstanceToString: ({Instance}) -> {string} = function(Array)
	for i = 1, #Array do
		Array[i] = Array[i].Name
	end
	return Array
end

For one, I had to wrap {Instance} in parentheses so that the arrow -> thing didn’t throw a syntax error. Now that I’ve done that, I am getting this error:
image

W000: Type ‘({t1}) → <CYCLE> where t1 = {- Name: t1 -}’ could not be converted into ‘({Instance}) → {string}’

I can barely decipher this, let alone understand it. Would anyone care to explain, or at least refer me to the right page?

2 Likes

Yeah, that’s a pretty confusing error message IMO :confused:

Check this out:

local Array_InstanceToString: ({Instance}) -> {string} = function()
end

… which gives this error:
image

Makes sense, the variable type declaration says it should take {Instance} and return {string}, but it takes nothing and returns nothing, so we get that error.

Now check out this:

local Array_InstanceToString: ({Instance}) -> {string}

function Array_InstanceToString(Array)
	for i = 1, #Array do
		Array[i] = Array[i].Name
	end
	return Array
end

basically, just declaring first then defining. That gives two errors:

image

This actually also makes sense. You declared that Array should be of type {Instance}, but you’re basically doing Array[i] = "string", i.e. assigning a string to something that you declared should be an instance. You’re trying to put a string into an instance array. Luau sees this and tries to implicitly convert the string to an Instance, but it can’t so you get that error meassage.

… and

image

You declared that Array is of type {Instance} and that the function must return a {string}. When you do return Array, Array still has type {Instance} so there’s a mismatch between what you return and what you declared earlier that you would return. Once again, Luau tries to convert your Instance array into a string array, which it can’t so it gives up and gives you the second error message.

The combined error message is still confusing as all heck tho :grey_question::grey_question::grey_question:

Check this out:

Instead of .Name it uses .Parent because I wanted to see if that’s what the error message was referring to. The beginning of the first part is clear, it’s saying that it’s trying to convert from one kind of function to another. The first type is a function of type

({t1}) -> <CYCLE> where t1 = {-Parent: t1 -}

which it tries to convert to the second type:

({Instance}) -> {string}

That whole LoC is one type. It’s a type of function that takes an Instance array and returns a string array.

As for that crazy cycle stuff, my best guess is that Luau figures out that the definition of the type the function takes is cyclical, or self-referential, because it can see that you’re turning objects of type t1 into objects of type t1.Name (or Parent because I changed it).


The reason that’s an error is that putting string values into an Instance array…

a) You can’t do that
b) It wouldn’t make the Instance array into a string array


The fundamental problem with your function is that you’re trying to put strings into an Instance array. I can see that you’re trying to avoid making a new table and instead do the conversion in place. AFAIK Luau doesn’t have an “as” keyword or any other way of treating an array of one type as if it were an array of a different type.

To fix your function, do something like

local Array_InstanceToString: ({Instance}) -> {string} = function(Array)
	local Result = {}
	for i = 1, #Array do
		Result[i] = Array[i].Name
	end
	return Result
end

or even

local Array_InstanceToString: ({Instance}) -> {string} = function(Array)
	local Result: {string} = {}
	for i = 1, #Array do
		Result[i] = Array[i].Name
	end
	return Result
end

which gives no errors but does allocate a new table for the return value.

2 Likes

I think what you’re looking for is this.

local function Array_InstanceToString(Array: {Instance}): {string}
	for i = 1, #Array do
		Array[i] = Array[i].Name
	end
	return Array
end
1 Like

Very helpful response - thanks for explaining how Luau checks this kind of stuff. Maybe I’m not entirely familiar with the purpose of typechecking notation like this, then - I was under the impression that all Luau did was check if the input array held water with how I specified (if it really was an {Instance} array) and then if the output array’s values matched as I entered as well ({string}). I didn’t think it would actually ensure the “safety” of the value type for the duration of the function.

Guess I’ll be sticking to nonstrict for something like this, then. I liked my original code, as I am not one to waste tables should they come my way :triumph:

2 Likes