Open virusdefender opened 4 years ago
@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:
true
is a common success value)(number, number) | (nil, string)
))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.
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
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.
for example
some related code
https://github.com/teal-language/tl/blob/master/spec/return/arity_spec.lua#L38 it should be
rejects in strict
?https://github.com/teal-language/tl/blob/8b3c19a82805e728b75ce5c27d9eab93b99293a1/tl.tl#L5401 [edited because
master
is a moving target]