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

Make TypeQuery more general, handling nonboolean queries. #3084

Merged
merged 6 commits into from
Apr 12, 2017

Conversation

sixolet
Copy link
Collaborator

@sixolet sixolet commented Mar 29, 2017

Instead of TypeQuery always returning a boolean and having the strategy be a (fake) enum, the strategy is now a Callable describing how to combine partial results. The strategy takes in an Iterable of the type it's going to return, and returns one of them. For ANY_TYPE_STRATEGY, use the builtin any, for ALL_TYPE_STRATEGY, use the builtin all.

This is a pure refactor that I am using in my experimentation regarding fixing #1551. It should result in exactly no change to current behavior. It's separable from the other things I'm experimenting with, so I'm filing it as a separate pull request now. It enables me to rewrite the code that pulls type variables out of types as a TypeQuery.

I now think this PR is a pleasant cleanup, and we should merge it 😄

Instead of TypeQuery always returning a boolean and having the strategy be an
enum, the strategy is now a Callable describing how to combine partial results,
and the two default strategies are plain old funcitons.

To preserve the short-circuiting behavior of the previous code, this PR uses an
exception.

This is a pure refactor that I am using in my experimentation regarding fixing
python#1551.  It should result in exactly no
change to current behavior. It's separable from the other things I'm
experimenting with, so I'm filing it as a separate pull request now. It enables
me to rewrite the code that pulls type variables out of types as a TypeQuery.

Consider waiting to merge this PR until I have some code that uses it ready for
review.  Or merge it now, if you think it's a pleasant cleanup instead of an
ugly complication.  I'm of two minds on that particular question.
mypy/types.py Outdated
multiple results. The strategy must be either
ANY_TYPE_STRATEGY or ALL_TYPES_STRATEGY.
"""
class TypeQuery(Generic[T], TypeVisitor[T]):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove Generic[T] from bases.

mypy/types.py Outdated
"""True if any type's result is True"""
if accumulated:
raise ShortCircuitQuery()
return current
Copy link
Contributor

@pkch pkch Apr 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe replace raising exception with returning a tuple of (current, short_circuit), and break in query_types loop when should_break is true? I don't think using exceptions to return a value is bad if it's a relatively less frequent condition, but in this case it will happen very often. Of course, in this case, all strategies would need to support this interface, so if you think it's too much, it's fine.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compare StopIteration for the paradigm I am trying to use. I thought about using raise StopIteration literally, but since this is not exactly an iterator I made my own specialized exception.

(In other words, I like it this way, but I would be open to the idea of using StopIteration instead of my custom thing if that seems cleaner)

mypy/types.py Outdated

Common use cases involve a boolean query using ANY_TYPE_STRATEGY and a
default of False or ALL_TYPES_STRATEGY and a default of True.
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe get rid of TypeQuery.default, and instead store it inside the strategy? In that case, all methods that currently return self.default would call self.query_types([]) instead. This would make things slightly more streamlined, as everything will be routed through strategy (in particular, a strategy would even be able to change the default for query result in case the list is empty).

@sixolet
Copy link
Collaborator Author

sixolet commented Apr 12, 2017

Ok, @pkch inspired me to make the strategy function just take an iterable instead of two items, simplifying things greatly. No more default; no more defined strategies (use the builtins any and all instead), less code, simpler code.

@sixolet
Copy link
Collaborator Author

sixolet commented Apr 12, 2017

(And it would now be useful to me to get this merged, because I'm going to start circling #3113 for a landing, and it depends on this)

@gvanrossum
Copy link
Member

gvanrossum commented Apr 12, 2017

Will try to review tomorrow. Or if @ilevkivskyi likes it enough he can merge!

Copy link
Contributor

@pkch pkch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@gvanrossum gvanrossum merged commit 5f2f110 into python:master Apr 12, 2017
@gvanrossum
Copy link
Member

Yee-haw!

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

Successfully merging this pull request may close these issues.

3 participants