Luau Recap: May 2020

Luau is already active, while type annotation is its strict mode. Without it, it will just automatically set the types.

1 Like

Backwards compatibility. Luau is practically a new language.

And default scripts like the health script, animate, etc don’t use typed Luau.

I worded it wrong, I meant that there would be no reason to use the old version of Roblox’s Lua. I don’t think typed lua should be forced.

The fact that we even saw problems with this is reason enough.
Typically our bar for introducing new syntax is “if all valid programs don’t change their meaning, we can introduce it”. For as we neglected to follow this and the consequences were that we actually broke production games - we’ll try to make sure it won’t happen again.

It’s really important to make sure that existing code still works because it avoids the need for forking the language or opting in into new features on a game-by-game basis.

2 Likes

This is neat but it’s not a complete solution - I think the interesting uses of as weren’t just about telling the type checker “don’t worry about this type”, but also about asserting the type for getting back into strict context where any isn’t a good enough type for everything.

Glad this was pointed out. So it turns out that, when a ModuleScript errors while being required, that error is unconditionally emitted to the output, and require instead throws a “Requested module experienced an error while loading” error. Normally, this would make it impossible for pcall&co to recover the original error and stack trace from the ModuleScript. However, debug.loadmodule basically packs the internal require into a function so that this information can be recovered. Unfortunately, loadmodule is currently locked behind a FFlag. FFlagEnableLoadModule

I’m not really sure why require has to behave this way. Errors that are unrecoverable and insuppressible are super annoying. If debug.loadmodule were enabled, I would see no reason to use require.

4 Likes

When looking at the changes to types, it seems none of the WaitForChild functions have their timeout parameter set as optional. For example on BasePart:

WaitForChild:(BasePart,string,number)->(any),

Shouldn’t it be number? instead of number?

3 Likes

The bug with this optimization has been fixed and it has been enabled.

This has been fixed.

2 Likes

debug.loadmodule returns the function object that represents the module, it doesn’t evaluate it. This is necessary for some unit testing workflows for global injection (we aren’t fully sure if we want to expose this yet which is why it’s not enabled yet iirc), but this means that there’s no cache of the resulting data. It’s not a replacement for require.

1 Like

How else do I recover/suppress the error thrown by the ModuleScript?

Isn’t Lua spelt wrong? Or is luau a older version?

Luau is the specific name for Roblox’s Lua compiler.

What does it cost to cache ModuleScript data?

Requiring modules via statements like require(script.Parent.Parent.Parent.Foo) or require(game:GetService("ReplicatedStorage").Modules.Utility.Bar is practically unusable for massive projects in my opinion. Some of us got tired of traversing the DataModel and just made their own module loader that caches the result itself.


This type of requiring would actually be quite useful for plugin development, because there’s no way to “restart” modules that are changed without cloning them, or break their connections without destroying them. Right now I need to create temporary ModuleScripts to achieve this. What I use works something like this:

local moduleScriptClones = {}
local function customRequire(moduleScript)
    local moduleScript2 = Instance.new("ModuleScript")
    moduleScript2.Source = "return function(script, require)" .. moduleScript.Source .. "\nend"
    table.insert(moduleScriptClones, moduleScript2)
    return require(moduleScript2)(moduleScript, customRequire)
end

I really don’t like that, but the ability to share modules between plugins and games is immensely valuable, especially when it’s paired with a module loader that can do inter-module simplification and remove unused modules/data.


I completely agree. It would be even more useful if it was possible to specify an error handler for threads that are created inside that module, so that errors like this can be easily suppressed and detected, especially in plugin environments:

game:GetService("RunService").Heartbeat:Connect(function()
    error()
end)

It’s also interesting how debug.loadmodule would influence what connections are bound to what scripts, and how that may be handled potentially. There are a lot of use cases for something like this.

Ideally pcall() would work here. Maybe we can make it work, unsure. This problem hasn’t been brought up before, which is why it still works the way it used to.

There’s a change in the pipeline to clear the module cache when the source changes.

1 Like

It seems that some userdata like Color3 are not fully implemented yet.
When you declare an argument type as Color3 and use CFrame in a different function, it accepts it without giving a warning because these are both “Vector3 values” containing 3 numbers. Only when you run the game, the error pops up.
Will this be fixed later on?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.