Luau Type Checking Beta!

The standard Lua solution to get the same result is:

return string == String and true or false
3 Likes

The conditional operator is more of a feature for “curly bracket” languages like C++, JavaScript, etc. Currently you can replicate this with a and b or c. However it messes up when b is falsey. "hi" ? false : true evaluates to false, but "hi" and false or true evaluates to true because of the nature of the and and or operators.

Btw a == a and true or false is redundant since the == operator always returns true or false

2 Likes

It’s been over a month and I’ve gotten no word on this bug, and it has not been fixed:

sorry for the month-late response…

The reason why the spawn function warns like it does is because the annotation for the inside function has to return nil instead of nothing, which is redundant:

-- current correct way of using spawn:
spawn(function() => nil -- or `nil?`
	print("stuff")
end)

The type surface from zeuxcg shows this:

-- somewhere down there,
-- inner fn annotation returns nil explicitly
local spawn: ( ()=>(nil) ) => (nil)

-- should be:
local spawn: ( ()=>() ) => ()

It would make more sense for literal nothingness and nil to be identical in type like how vanilla Lua treats it.

4 Likes

Might have something to do with userdatas not being fully supported yet. The editor believes that tables are the only objects you can call methods on or set values to.

I also get a similar "Not a table: ImageButton|Texture|nil" error in my __newindex metamethod:
self.Instance.Texture = v1

1 Like
setmetatable({},setmetatable({},{}))

safsafsafasfa

image

These warnings doesn’t make sense.

1 Like

I think it was because the game not recognize that it are empty tables.

Hello, sorry for annoying you, but i still have a question: If we make a Function and we want to indicate a Parameters that was a Part, how to attempt this, @fun_enthusiast?

This was my idea:

local PartReference = Instance.new("Part")

local function Test(Part: PartReference)
    --Does this work
end
--Else

local function OtherPossibility(Part: Instance)
    --Or this was the best?
end

If i indicate that it was a Instance, it will sure work, but it not know that it was a Part. If here was a possibility to full indicate that it was a Part, how to attempt it or it was simply not possible?

It seems if you have strict mode on you can just do this:

--!strict
local Part = Instance.new("Part")
local Sound = Instance.new("Sound")

local function Test(part: Part)
	
end

Test(Sound) -- not ok
Test(Part) -- ok
1 Like

@Nezuo, i not am using strict mode, then i am new with Luau. Was here not another way to make it (Without the strict mode)?

Non-strict mode is for backwards compatibility so script without types still work. This is why a non-strict typed script does not error when you don’t pass in a Part. Strict mode makes it so it will error if the passed argument is not the right type. If you want to use types, I would suggest using strict mode.

It’s likely because functions do not necessarily return a single value. In this case it should know that setmetatable has a single result, but wrapping the final argument in parentheses should silence the warning:

setmetatable({}, (setmetatable({}, {})))

It’s inconvenient, but I recommend wrapping the final item in an array with parentheses if it’s a function call. This both improves performance, and prevents possible bugs if you decide your function should return more than one value later:

{foo(), foo()}

{foo(), (foo())}

You may also do this for returns or function call arguments, but the performance impact isn’t as significant.

Actually, are there cases where providing the results of a call like this can cause deoptimizations @zuexcg?
For example, how does this:

for i, v in ipairs(foo()) do
end

local bar = math.abs(foo())

compare to this:

for i, v in ipairs((foo())) do
end

local bar = math.abs((foo()))
2 Likes

I am kind of confused with how I would use the function type. Is it used like this?

type sumFunc = (number, number) => number

local function add: sumFunc(intA: number, intB: number) => number
    return intA + intB
end

We didn’t add the syntax to annotate the type of a function directly because you don’t need to use the function type when you’re declaring a local function, you’ve already said that this add is a function. So you would still write it as…

local function add(x: number, y: number) => number
  return x + y
end

Which says that add is a function that takes two numbers and returns a number, just like your type sumFunc = (number, number) => number example.

There’s another way to write it, but at least using the sumFunc type…

type sumFunc = (number, number) => number
local add: sumFunc = function(x, y) return x + y end
1 Like

The function type doesn’t seem that useful to me. Any use-case for something like this? At this point I would just declare the parameter type and return type without needing to make it a function type

1 Like

One use case is callbacks, where you want to pass arguments to a function (the function is just a variable that we “call back”), but there are a number of different functions that can implement your callback function type.

Example:

local function loopEverySecond(callback: (number) => void)
    while true do
        local deltaTime = wait(1)
        callback(deltaTime)
    end
end

loopEverySecond(function(deltaTime)
    print(deltaTime, 'has elapsed')
end)

In this case, the callback parameter of loopEverySecond is typed as a function, (number) => void, and because we know this callback takes in a number as its first parameter, we don’t actually need to give a type annotation to deltaTime in this block:

loopEverySecond(function(deltaTime)
    print(deltaTime, 'has elapsed')
end)

deltaTime is inferred to be a number, because our callback function is typed as (number) => void. I’d imagine once typed Luau is developed further, the intellisense will let you hover over a variable to see its type, revealing that deltaTime is indeed assumed to be a number despite the fact that we didn’t annotate it with deltaTime: number

1 Like

After playing around with the type checking, I concluded the usage of typed function like this. Thanks for the assistance :smiley:

type blah: {
    Blahh: sumFunc
}

type sumFunc = (number, number) => number

local Blah: blah = {}

function Blah.Blahh (a,b)
    print(a + b)
    return a + b
end
1 Like

Will we ever see operators such as +=, -=, *= etc?

2 Likes

(I’m not sure if my question is already answered)
Tell me if I am correct or not, for now the new type checking in author time is just there as a quality of life?

Since we’re getting ‘static/strict’ typing anyway, is it possible that with strict mode, performance is increased by removing the overhead of type checking in runtime and other lovely things?

Nah, or at least not anytime soon. If you scroll up a bit, zeuxcg explains why. But either way there would be a lot to consider.

Suppose you have this

a = setmetatable({ }, { __index = { b = { c = 5 } } })
a.b.c += 5

Table access can be overloaded. Should this expand to

local b = a.b
b.c = b.c + 5

Or to

a.b.c = a.b.c + 5

In the second example, __index would have fired twice, which may or may not be desirable. Additionally, since arithmetic operators can be overloaded, should compound operators respect the overload? Those are probably a few things that need to be well-defined, though I won’t say it’s 100% impossible since im not a roblox engineer

4 Likes