-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
methodswith does not act as I expect it to, and others may have the same feeling (e.g., discourse1, discourse2, discourse3). Let me first acknowledge that methodswith seems to have a primary mission as a discoverability tool, and when it violates my expectations the differences seem mostly due to me trying to get it to be a tool for systematically exploring the complete collection of Julia methods. It is quite possible that the thing to do here is have a MethodsWith package that behaves differently from InteractiveUtils.methodswith, but I thought I'd start here and see how much of this should move into InteractiveUtils. A PR to fix these is ikely to come soon, but to centralize discussion about design (vs. implementation) I thought it might be best to separate the issues in a mini-Julep.
The docstring description "Return an array of methods with an argument of type typ" is not so detailed as to count as a concrete specification. If I try to formalize what I want out of this function, I come up with a partial specification (one applicable to the methodswith(type, f) syntax) like the following:
methodswith(typ, f; some_magic_keywords) == methods(f, Tuple{typ}) ∪ methods(f, Tuple{typ,Any}) ∪ methods(f, Tuple{Any,typ}) ∪ ...where the idea is that typ can be in any positional slot. Moreover, I would then expect
methodswith(typ; some_magic_keywords) == ∪ᶠ methodswith(typ, f; some_magic_keywords)where ∪ᶠ means the union over all functions f.
We do not currently seem to have anything that behaves this way.
methodswith has a limited search strategy
Without the f, as mentioned in methodswith's docstring it doesn't search unexported functions or descend into submodules, and there is currently no way to force it to do so. Consequently methodswith might miss many methods that operate on the specified type.
Possible solution: add an all keyword argument (default value false) that gets passed on to names, allowing one to force it to also search unexported functions. Likewise, a submodules keyword argument (default value false) would allow one to force the search to include non-top-level modules.
methodswith has inverted specificity with respect to methods
In abstract/concrete type hierarchies, the sense of specificity between methodswith and methods is inverted, as can be shown with
abstract type Super end
struct Sub <: Super end
fS(::Super) = 1
fS(::Sub) = 2It turns out that methodswith(Sub, fS; supertypes=true) matches methods(fS, Tuple{Super}), but there is no way to get it to give the same result when using Super as the typ argument to methodswith.
Possible solution: add a subtypes keyword argument (default value false) that would allow one to force it to use the same subtyping rules as used in methods.
Parametric signatures can be missed if one doesn't supply the exact parameters
Consider
f1(::Vector) = 1
f2(::Vector{Int}) = 1
f3(::Vector{I}) where I = 1
f4(::Vector{<:Integer}) = 1Among these, methodswith(Vector, fn) (without any supplied parameters for Vector) returns no methods for f2 and f4 even with the supertypes=true. However, f3 works as expected.
Proposed solution: this might be just a bug; fixing it would change the output of methodswith so is technically breaking, but if we view it as a bugfix this makes it OK.
TODO
- decide which of these belong in
InteractiveUtilsand which in aMethodsWithpackage - implement the changes