Skip to content

Mypy complains about lambda that returns None #1425

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

Closed
JukkaL opened this issue Apr 22, 2016 · 7 comments
Closed

Mypy complains about lambda that returns None #1425

JukkaL opened this issue Apr 22, 2016 · 7 comments
Labels
bug mypy got something wrong

Comments

@JukkaL
Copy link
Collaborator

JukkaL commented Apr 22, 2016

Mypy gives a bogus error when giving a lambda that returns None when a callable returning None is expected:

from typing import Callable

def f(x: Callable[[], None]) -> None: pass

# Argument 1 to "f" has incompatible type Callable[[], None]; expected Callable[[], None]
f(lambda: None)  

Likely this is due to Void vs. NoneTyp, and we'd have to replace an inferred NoneTyp of a lambda expression with Void.

@JukkaL JukkaL added the bug mypy got something wrong label Apr 22, 2016
@gvanrossum gvanrossum added this to the 0.4.x milestone Apr 28, 2016
@gvanrossum
Copy link
Member

Possibly this would also be fixed once we introduce strict Optional checking.

@JukkaL
Copy link
Collaborator Author

JukkaL commented Apr 28, 2016

Maybe -- we'd likely still want to keep no return value from a function and a regular None value separate concepts, though.

@ddfisher
Copy link
Collaborator

Would be fixed by #1278, which will likely happen as part of strict Optional checking.

I actually think we will not want to have no return value distinct from regular Nones once we have strict Optional checking. It adds extra complexity (both in code and for users), and shouldn't check any important cases that Optional checking wouldn't catch.

@gvanrossum
Copy link
Member

gvanrossum commented Apr 28, 2016

I actually think we will not want to have no return value distinct from regular None [...]

But PEP 8 states:

Either all return statements in a function should return an expression, or none of them should.

It then shows two "No" examples. I would like mypy to catch those:

def foo(x):
    if x >= 0:
        return math.sqrt(x)

def bar(x):
    if x < 0:
        return
    return math.sqrt(x)

even though they would be annotated with -> None. (The "Yes" examples are uninteresting -- they should just use -> Optional[something].)

@ddfisher
Copy link
Collaborator

For foo(): I'd like mypy to catch that too. I think it's reasonable to expect all functions that don't return None (even if they do return some Optional type) to have explicit returns on all possible execution paths. That'll require some control flow analysis, though, so I don't think we should aim to have it in the first version of Optional checking.

For bar(): If the type of bar() is Optional[float], I we should only produce an error on this code if we provide a flag to turn it off. It's solely a style issue and not one of correctness -- if there are people out there who have been inconsistent about return vs return None, I don't think we should force them to fix it before adopting mypy. In general, I think enforcing style constraints should be considered secondary to mypy's primary goal of enforcing correctness, and that any purely stylistic error should have a flag that turns it off (and that we should perhaps also have an aggregate flag that turns off all style warnings).
If the type of bar() is not an Optional type, then the no-argument return statement should produce a error.

@gvanrossum
Copy link
Member

Both foo() and bar() have Optional[float] as type. Both have a style error; I don't consider falling of the end different from a return without value in the middle.

I think it's reasonable if mypy enforces things that could be considered style issues, and I don't think we always need to provide a way to turn them off. (Taken to the extreme, being consistent in the return type is a style issue too.)

@ddfisher
Copy link
Collaborator

Hmm. I agree that both of those are style errors. I think the former is slightly more likely to be accidental than the latter, but I think I was wrong to propose that they be treated differently.

I also think that it's reasonable for mypy to enforce style issues, especially when they may have correctness implications (e.g. forgetting to actually write a return statement is pretty common in my experience). I'm not sure we always need to provide a way to turn them off, but I think we should consider it on a case-by-case basis, because they have the potential to be unnecessary roadblocks to people using mypy.

I actually do think there's a reasonable line we can draw between style and correctness issues -- it can be fuzzy at times, but by and large I think it's a distinction worth making.

rwbarton added a commit to rwbarton/mypy that referenced this issue May 20, 2016
"lambda: None" might be used either where a function returning an
Optional[T] is expected, or where a function not returning a value is
expected. Previously it would always treated as the former; now the
context is used to decide.

When no context is available, the lambda is now treated as a function
not returning a value. This seems more consistent with the fact that
you can't define a variable 'a = None' without a type annotation or
declare a function to return NoneTyp. (If really desperate for the
other meaning of "lambda: None", you can write a generic function.)

Fixes python#1425.
rwbarton added a commit to rwbarton/mypy that referenced this issue Jun 15, 2016
"lambda: None" might be used either where a function returning an
Optional[T] is expected, or where a function not returning a value is
expected. Previously it would always treated as the former; now the
context is used to decide.

When no context is available, mypy continues to treat the lambda as
returning the value None, rather than no value at all. When the other
meaning is desired, it is generally possible to provide a context, or
in any case to use a function defined with `def`.

Fixes python#1425.
rwbarton added a commit to rwbarton/mypy that referenced this issue Jun 15, 2016
"lambda: None" might be used either where a function returning an
Optional[T] is expected, or where a function not returning a value is
expected. Previously it would always treated as the former; now the
context is used to decide.

When no context is available, mypy continues to treat the lambda as
returning the value None, rather than no value at all. When the other
meaning is desired, it is generally possible to provide a context, or
in any case to use a function defined with `def`.

Fixes python#1425.
ddfisher pushed a commit that referenced this issue Jun 15, 2016
"lambda: None" might be used either where a function returning an
Optional[T] is expected, or where a function not returning a value is
expected. Previously it would always treated as the former; now the
context is used to decide.

When no context is available, mypy continues to treat the lambda as
returning the value None, rather than no value at all. When the other
meaning is desired, it is generally possible to provide a context, or
in any case to use a function defined with `def`.

Fixes #1425.
cpdean added a commit to cpdean/zulip that referenced this issue Jun 22, 2016
cpdean added a commit to cpdean/zulip that referenced this issue Jun 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

3 participants