Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

check return value and argument number #100

Open
virusdefender opened this issue May 9, 2020 · 3 comments
Open

check return value and argument number #100

virusdefender opened this issue May 9, 2020 · 3 comments

Comments

@virusdefender
Copy link

virusdefender commented May 9, 2020

for example

local function a(i: number): number, number
    if i == 1 then
        return 1, 2
    else if i ==2 then
        -- should check return value number
        return 3
    else
        -- should check if there is no return
    end
end

local x = a(1)
-- should check receiver variable number
local x, y = a(2)
-- should check argument number
local x = a()
Type checked main.tl
0 errors detected

some related code

https://github.com/teal-language/tl/blob/master/spec/return/arity_spec.lua#L38 it should be rejects in strict?

tl/tl.tl

Line 5401 in 8b3c19a

if #children[1] > nrets and (not lax) and not vatype then
[edited because master is a moving target]

@virusdefender virusdefender changed the title check argument number check return value number May 9, 2020
@virusdefender virusdefender changed the title check return value number check return value and argument number May 9, 2020
@hishamhm
Copy link
Member

hishamhm commented May 9, 2020

@virusdefender Thanks for the report! This is a tricky one.

This is very much related to #71, except that that one is about input arguments to a function, and this one is about output values.

The reason why Teal (currently) accepts missing return values is because any return value may be nil (because any type may be nil).

It is a very common pattern than functions in Lua will return sometimes one, sometimes two values:

function f(x)
   local result = x * 2

   if x < 10 then
      return nil, "oops"
   end

   return result
end

The "real" result type of f (the one that lives in the Lua programmer's head) is "either number, or a nil followed by a string". Note that this is different from number, string and from number?, string? (Teal doesn't even support T? yet). This is more like (number) | (nil, string), which is a sort of "union type on implicit tuples".

How to destructure this type on the caller gets pretty tricky. Common Lua pattern:

local x, y = f()
if not x then
   print("error: " .. y)
end

The above looks logical (if x is nil, then y is string), but it has a bunch of things to consider when making the compiler smart enough to understand this:

  • what it if the valid result of f was not number but boolean? (true is a common success value)
  • what if the valid result value was multiple values, as in ((number, number) | (nil, string)))
  • what if other conditional assignments happen in between? (this needs to be a proper flow analysis)

It goes on and on...

Putting all that aside, the simplest strict thing would be to force an explicit arity on the return values. So, if the return is number, number and you want to return nothing on an error, you have to return return nil, nil.

This is the simplest to implement, but I think it would be pretty annoying to use, because considering error results of the type nil, string, this means that every function that returns errors becomes a multiple-return function, so you have to keep returning as return result, nil on every non-error return.

Another option, would be to do the same as what is considered on #71, and add notation not about nullability, but about explicit arity (that is, the number of return expressions, regardless of their values and types).

One issue with that is syntactical: how to specify it? In #71 the ? notation is added to the variable names. But there are no variable names in returns... The best I can think of is this:

function f(x: number): number, ?string
   local result = x * 2

   if x < 10 then
      return nil, "oops"
   end

   return result
end

...which is pretty ugly. I did not pick the string? notation because that generally represents nullable types, and not arity — but maybe we could do that if we consider that ultimately, ?string and string? would work the same for result values, in a future version of Teal that had nullable types (I believe this is different from TypeScript because we don't have to deal with the undefined vs. null question.)

Sorry for the braindump here, but I thought it was useful to write these thoughts down! I'll give this some more thought and possibly experiment with this a little.

@virusdefender
Copy link
Author

virusdefender commented May 10, 2020

Thank you for the quick reply

This is the simplest to implement, but I think it would be pretty annoying to use, because considering error results of the type nil, string, this means that every function that returns errors becomes a multiple-return function, so you have to keep returning as return result, nil on every non-error return.

This is necessary for code robustness, and it's also a common pattern in golang https://blog.golang.org/error-handling-and-go . BTW, there is no optional argument in golang, it's not a problem.

Under my scenario, i want to force programmers to check errors like golang to avoid bugs, such as file operation, or there will nobody to check if the operation is successful, and then the pass the return value (may be a nil) to the next block and then cause some bugs.

The reason i chose teal-lang is that it can help to to deal with above issues, using lua like a static language, i think the goal of teal-lang is not only to provide types, but also help to write more safe and robust code.

Maybe teal-lang can provide a more strict mode to check code? At the first stage, the hard flow analysis can be skipped, the goal is to check the direct return statement variable number.

local function a(i: number): number, number
    if i == 1 then
        return 1, 2
    else if i ==2 then
        -- it's easy to check, i think
        return 3
    else
        -- need flow analysis?
    end
end

@hishamhm
Copy link
Member

Maybe teal-lang can provide a more strict mode to check code?

That's an interesting idea. The stricter check of arity could be a warning flag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants