Luau Type Checking Release

Sure, here’s a model file for each one:

Key 'constructor' not found in table '{ @metatable any }'

IndexedEvent.rbxm (4.1 KB)
Should be in the module “IndexedEvent”, line 90
image

Key 'constructor' not found in table 'Spring'

Spring.rbxm (2.9 KB)
Line 142
image

1 Like

I think they have a tab on performance here:
link
Not sure if you’ve checked, or it doesn’t answer the question but I tried anyways

The whole “Anchored” not showing up in Instance is caused by something simple. Instance does not have BasePart properties, make sure it’s actually a type BasePart. If you use a question mark that means it doesn’t have to be a Part.

local i: BasePart = Instance.new("Part")
if typeof(i) == "Instance" then
    print(i.Anchored) -- expected result: false
end
1 Like

If using the new type annotations and strict mode will yield performance improvements in the future then I really hope by then there’s a solution to elegantly converting OOP. Right now converting plain Lua OOP to Luau is tricky and I have yet to find an interim solution that scales well and doesn’t involve things like:

type ClassName = typeof(Class.new())

This is not performant or elegant code especially if the constructor of the class does more than just initialising some members, Also what if the constructor takes args such as an instance of another class in order to create the instance? It’s just wasting CPU time.

2 Likes

In my example

--!strict
local i:Part? = Instance.new"Part"
if typeof(i) == "Instance" then
	print(i.Anchored) -- W000: Key 'Anchored' not found in class 'Instance'
end

i has two possibilities:
nil
Part

If i is an instance then it has to be a Part, the only other possibility doesn’t satisfy typeof(i) == "Instance"

i must be a Part or nil

--!strict
local i:Part? = Instance.new"Part"
i = Instance.new"Frame" -- W000: Type 'Frame' could not be converted into 'Part | nil'
1 Like

TBH not interested in typed Lua at all, I like Lua as it is. But if types are gonna be critical to big performance gains down the road, that’s all you needed to tell me chief.

2 Likes

How much performance do you think this will give once it is fully released? Also does it matter what type check you use even if you type check every variable?

Will there ever be support for custom types? Maybe square brackets will specify that the type variable will be a custom type. You would then specify a tuple which would include the original types inside of the square brackets. It could theoretically look something like this:

local boolAndNumber = [boolean, number]

function TypeFunction(param: boolAndNumber)
 return param
end
print(TypeFunction(39))
--// Which this should promptly print 39

This would allow for more customizable code and a way to better filter out unwanted variables. In the future maybe the type checker will ignore a variable that doesn’t correspond with the type declared.

PS: What’s up with export? I always see it in the Beta version of Studio but I never figured out what it did. Is it unfinished? If so, why add a keyword that doesn’t work yet?

Custom types do exist via the type keyword:

type A = {x: number, y: number, z: number?}
type B = {x: number, y: number, z: number}

local a1: A = {x = 1, y = 2}        -- ok
local b1: B = {x = 1, y = 2, z = 3} -- ok

local a2: A = b1 -- ok
local b2: B = a1 -- not ok

By the way, I got this code from Type checking - Luau. You could also go there to further learn about types and luau in general.

2 Likes

Will there be a way to enable real-time studio-only type assertions? I’d like to get a warning when I assign a variable to the wrong type, but I wouldn’t want it to slow down the live game.

Also, is there a standard way to define a basic “table” or “function” type? I have a lot of code that uses both the array/hash/metatable parts for various things, but I still want to define it as a table. I sometimes get warnings when I use “{}” (I don’t have an example right now.)

There’s also a stringless-object pattern I use everywhere in my game to reduce memory both per-script and per-table. It would be nice to have some support for stringless classes stored as arrays:

local key_Health = 1
local key_MaxHealth = 2
type HealthState = {[1]: number, [2]: number}

In other development environments it’s possible to have class member debug info stripped from your compiled source code (because everything is explicitly typed.) Unless something like that is made possible I’m going to continue doing this; Having strings in your code for each member in a class is equivalent to storing variable names in your script’s debug data.
It’s insignificant for small projects, but it really adds up for massive codebases with tons of unique member names.

9 Likes

Wow, this is great! Type checking will be so useful, especially when simplified bytecode begins to be generated.

That being said, I think there should be some changes to the way that a script is declared Strict, NonStrict, and NoCheck. I say this because the current way, adding a comment to the top of the script, seems like bad practice and might take up space where the scripter wants to add another comment. Instead, it should be an enum property of the LuaSourceContainer class. This also would clarify the difference between certain scripts to new users, and it would allow for devs to more traditionally manage their code. In Lua, comments are supposed to be ignored by the bytecode compiler but it seems contradictory to have that define the interpretation style of all of the rest of the code. Having it be an enum would allow for people to more quickly understand the difference between type checking scripts and non-type checking scripts.

5 Likes

I like having better type checking with Luau / Lau on the Roblox Engine whenever I script something, will help me out a lot in present, future and past scripts to find broken or recommend fixes. :happy3:

However, I agree with @Crxzycar about adding a comment like --!strict onto the top of my scripts, having comments at the top is a bad practice and way to place comments as in most of my scripts I have comments for script updates, versions, and what to look out for in my development team as I open them up fresh for notes and changes to games. I don’t find it a problem to add a comment (--) to scripts, having it built-in in the future or property of the script(s) would seem nice to have within scripting.

RIP. When I first checked this out without read this, I thought mine wasn’t working when using --!strict and --!nocheck, it’s nice that it isn’t set my default, can the default in the future of type checking be set to either --!nonstrict or --!strict? I wouldn’t like nocheck to be default.

Will more updates for Luau type checking be coming with better catching with misspelled functions / variable names and more? I would like to see better checking happen in the future.

Overall, I do like what’s coming to Luau with type checking and the new W000 / W001 errors from these functions, will the documentation for the Script Analysis page get an update for this or a “nay”? I’ll keep using Luau and components for scripting, very helpful!

:+1:

4 Likes

This one… I’ll be very happy to see it.

2 Likes

I am really looking forward to the autocomplete and type ascription!

1 Like

Are you meaning something like a new script property? Sort of like

script.ScriptType = Enum.ScriptTypes.Strict

If not then I would like to know because i do agree with you on how the declaration of the script type thing doesn’t make “logical” sense.

2 Likes

It’s really helpful thing, i love it, but is there any possibility to have something like self when typing types which will refer to the variable name, it sounds bad and i guess it is but here is what i mean

local TestService: self =  game:GetService('TestService') -- self will refer to the variable name and get class TestService
TestService:Message()

It might be useless in most cases but i like to type names of services by their actual full names so this would make it look better and faster than

local TestService: TestService = game:GetService('TestService')

In my experience as a scripter, it’s a puzzle trying to figure out what broke my entire block of code that was working completely fine yesterday, searching for hours on the forum in hopes to solve my problem, only to find that I spelt “workspace” slightly wrong.

This update is a godsent-miracle solution for this problem, and I couldn’t be happier over such a small change :sweat_smile:

I’m not sure if this would be better.

  • A new enum type would further bloat the API.
  • It wouldn’t be reasonable for a game to set this property in real time, as it could affect the generated instructions.
  • Coders can visually see their scripts settings when previewing code, without needing to select it and opening the properties pane.
  • The comment format can easily be used by external tools like git.

Perhaps there could be a compromise between the two, where there is a property for storing things like --!strict and external type references / dependencies, but comments are really the simplest option.

I think comments are fine so long as their consistent about the format (--!foo / --[[!foo]] at start of script.) While I agree comments are a bit hacky, there is precedent for hacky ways to invoke strict mode in languages like JavaScript. I don’t think Luau strict mode is ready though; There are still warnings for regular use cases, and perhaps future updates that break old strict code (like real-time type assertions) could even improve performance because types can be assumed throughout instructions.

1 Like

The type of those variables should be inferred, so you don’t need a type annotation. If you don’t any point, that’s a bug and you should report it.

3 Likes

image
This results in a cannot call non-function warning, even though if it is nil it won’t get to the data.func()

--!strict
type test = {
	func: ()->()|nil
}

function run(data: test)
	if data.func then
		data.func()
	end
end
2 Likes