-
Notifications
You must be signed in to change notification settings - Fork 75
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
Upstream integration of some new features #78
Comments
This is definitely some great work. I'm not sure how important backward-compatibility is, but I'll hazard a guess and say "not very important". In any case, if you could break these features into chunks and send separate PRs I'd be all for it. Monster commits tend to be hard to manage. |
Yes, I'll definitely try to split as much as I can. That's one of the reasons for which I want to have feedback of the people involved: if you think that something is not interesting I will skip preparing that PR. I forgot to mention two things:
|
Python 2 support is definitely needed. I believe @shoyer planned to use this in XArray if a suitable solution was found, and XArray needs Python 2 support. However, I'm just a passer-by. |
So, I tried running the tests with python 2 and the only issues were with annotations (python 3 only), nonlocal keyword (which I can easily fix), and a few times with inspect.signature (something similar to that is already used in the master version, so I can look there). Overall, I am confident that I can make the code python 2 compatible. |
Thank you for itemizing the changes, it makes it much easier to understand all store dispatched objects in moduleI am not sure why you need to store the new dispatches in a module, it wasn't dispatch decorator for typesThis seems like a nice to have, but I think there might be a way to do this in a replace dispatchesI personally don't think this is a good idea from a maintainability homogeneous collections dispatchingI still don't think dispatching on homogeneous collections require modifications I would like to say again that I don't think that we should rely on pytypes for methoddispatcher inheritanceWhat is broken about the inheritance case now, shouldn't subclasses dispatch In [1]: from multipledispatch import dispatch
In [2]: class C:
...: @dispatch(int)
...: def f(self, a):
...: print('int')
...: @dispatch(float)
...: def f(self, a):
...: print('float')
...:
In [3]: class D(C):
...: pass
...:
In [4]: D.f(1)
int
In [5]: D.f(2.0)
float allow lambdas for typesThis is interesting, but I am not sure how useful it is. If this is a method strip None from tailThis could cause a change in behavior because it affects how existing functions ambiguity warning/errorYou can already turn this just this warning into an error using a warning custom exception for dispatch failuresThis seems fine assuming it is a subclass of general backwards compatibility
I think it is very important. I use multipledispatch in multiple productions |
I will reply to you in several posts. Concerning methoddispatcher inheritance: this one does not work with current master
|
To be honest I am also heavily using it for actual static class attributes, as in the tests. However, (even though the example is a bit silly) one could use it like this
to make sure that G1 objects can only be multiplied by G1 objects, and not by F or G2 objects. |
on ambiguity warning/error: I do agree on error by default, let's wait on other opinions. |
OK, I can limit this feature to my code where I need it. I thought this could have been a feature of general interest. I'll stay tuned to hear from anybody else if they might be interested in this. |
It is indeed a subclass of NotImplementedError |
I don't recall, but hopefully git history would have something. I suspect that it was just annoying to have a special type. Presumably subclassing would avoid this concern but for some reason, historically, it didn't. With any change like this I always ask "why is making our own way of doing things necessary?" I think that the default should be not to do this if possible and that any attempt to do it should be accompanied with concrete applications where it is necessary. |
Your point here is that my custom implementation of supercedes() and consistent() functions |
I am sorry, I do not get how this could break existing codes. None would get stripped from both |
I'll admit that this was originally driven by my need to programmatically generate modules, so there might be a I have to point out, however, that (unless I am mistaken)
This is no good for classes, because the following pseudo-code would not work
This is the reason why, for classes, I am requiring to store the Dispatcher somewhere else I attach a complete, yet simple, example. |
Let me comment a bit more on backwards compatibility for what concerns storing Dispatchers in module. The obvious compatibility brekage is the name in kwarg and the underlying storage. If you were willing to accept that, these would be the compatibility for each case (class, method, function, with/without kwarg):
Right now this case is disabled because I deem it confusing if one is willing to dispatch on F (see second snippet in my previous post). However, for the sake of compatibility with the current interface, I can enable it.
This is the use case that I have in mind for my second snippet in the previous post. The only compatibility breakage is the obvious one, the kwarg name.
This is the same behavior as current master.
This is the same behavior as current master.
Apart from the obvious compatibility breakage on kwarg name/value, this introduces another incompatibility with current behavior. Indeed, if I remember correctly, in current master print(f) would return Dispatcher , rather than function f. If we were willing to go down the module kwarg road, I would strongly argue in favor of my proposed behavior (even though it introduces another incompatibility) because otherwise cases 2 and 6 would be asymmetric. |
You can get the behavior you want for classes by creating the Dispatcher ahead of time and registering types into it; for example: In [1]: from multipledispatch import Dispatcher
In [2]: literal = Dispatcher('literal')
In [3]: @literal.register(int)
...: class IntLiteral:
...: def __init__(self, value):
...: self.value = value
...: def __repr__(self):
...: return f'{self.value} :: int'
...:
In [4]: @literal.register(float)
...: class FloatLiteral:
...: def __init__(self, value):
...: self.value = value
...: def __repr__(self):
...: return f'{self.value} :: float'
...:
In [5]: literal(1)
Out[5]: 1 :: int
In [6]: literal(1.5)
Out[6]: 1.5 :: float
In [7]: isinstance(literal(1), IntLiteral)
Out[7]: True
In [8]: isinstance(literal(1.5), FloatLiteral)
Out[8]: True In this case, |
Thanks @llllllllll for the example. Please allow me to play devil's advocate. Wouldn't your last statement
hold as well for the namespace kwarg? (replacing the word module with the word dict) |
Closing due to inactivity. |
Dear multipledispatch developers,
I have done some customization to multipledispatch to fit the need of one of my libraries.
While some of the changes are very specific to my needs, I think that most of the changes might be interesting to commit upstream.
The patched version of @dispatch decorator is available at this link, as well as some unit tests.
I would like to have your suggestions on which (if any) of my changes you would deem interesting upstream. I try to summarize them here:
do not store Dispatchers in a dict, but rather in a module. Note that this BREAKS backward compatibility. The motivation for doing this are strongly related to my specific needs (there is some summary in the multiline comment at line 366, but nonetheless I think that it might be a more natural way to store Dispatchers and being able to import them. There are a few tests on this: lines 366, 394.
allow @dispatch to be applied to classes. Tests at line 500, 647. This feature depends on the backward incompatible change concerning Dispatcher storage inside a module (rather than a dict).
allow dispatched functions to be replaced through @dispatch kwargs replaces=... and replaces_if=... . Implementation from line 79. Test at line 459, 669, 715. This feature depends on the backward incompatible change concerning Dispatcher storage inside a module (rather than a dict).
implementation of dispatching based on subtypes for dict, lists, tuple etc. This is already discussed in issue Dispatching to list subtypes #72, and there is also a WIP pull request WIP: Experiment to use pytypes to add support for python type hints #69. My implementation is very different from the two aforementioned approaches, and relies on custom defined classes named list_of(TYPES), tuple_of(TYPES), set_of(TYPES), dict_of(TYPES_FROM, TYPES_TO), where TYPES could be a tuple of types. I had laid out this part before learning about pytypes, so I am open to suggestions on replacing my custom made classes with pytypes. However, I personally do not like the square brackets in their notations: when declaring a @dispatch to take either int or floats one would use @dispatch((int, float)), where "OR" is denoted by a parenthesis, while for pytypes object on would need to write @dispatch(Tuple[int, float]), where "OR" is denoted by a square bracket. The notation of my implementation is instead list_of((int, float)). More implementation detail:
There are a few tests on this part:
have MethodDispatcher account for inheritance. In the current master version, dispatched methods are not inherited. The work from line 192 to line 307 allows dispatched class methods to be inherited and possibly overridden. Tests for this are at line 967, 993, 1002, 1040.
allow lambda functions to be passed instead of hardcoded types. The typical use case for which I needed this was in the definition of arithmetic operators, e.g.
Python interpreter fails on @dispatch(F) because F is not fully defined yet. My proposed solution has thus been to use
Note that in this case the evaluation of the signature is delayed to the first time the dispatched method is called.
Tests for this feature are:
compatibility with optional default None argument. Implementation at line 732, test at line 1193
@overload''' rather than
@overload()'' if the signature is provided through annotations. Implementation at line 419, test at line 1169. This is essentially a duplicate of @dispatch, so I might be willing to rename it back to dispatch before pushing upstream.Apologies for the long post, necessary to clearly present all features of the patched version of the library in order to understand from you which features might be of general interest.
ping @mrocklin @hameerabbasi @llllllllll @mariusvniekerk @shoyer who were involved in the aformentioned issues and pull requests.
The text was updated successfully, but these errors were encountered: