Specify a method to `!in`

In a function that takes a function as argument, it is clear how to provide a method specific to a named function (e.g. in by using ::Base.Fix2{typeof(in),T}). But it is unclear to me how to do the same thing for !in. If I make a method with signature ::Base.Fix2{typeof(!in),T}, it is never called. In code:

julia> struct A end;

julia> g(::Base.Fix2{typeof(in),A}) = nothing;

julia> g(::Base.Fix2{typeof(!in),A}) = nothing;

julia> g(in(A()))

julia> g(!in(A()))
ERROR: MethodError: no method matching g(::getfield(Base, Symbol("##54#55")){Base.Fix2{typeof(in),A}})
Closest candidates are:
  g(::Base.Fix2{getfield(Base, Symbol("##54#55")){typeof(in)},A}) at REPL[3]:1
  g(::Base.Fix2{typeof(in),A}) at REPL[2]:1
Stacktrace:
 [1] top-level scope at none:0

Am I correct to expect this to work?

in(A) produces a Fix2 object, but !in(A) produces a generic function. To make this work you’d want to define something like:

Base.:!(f::Base.Fix2{typeof(∈)}) = Base.Fix2(βˆ‰, f.x)
Base.:βˆ‰(A) = Base.Fix2(βˆ‰, A)

Note, however, that this is type piracy, so if multiple packages try to do this then they will conflict.

2 Likes

Thanks, this is helpful. I was hoping for a more general/straightforward solution, but this makes sense.

So a better place to do this might be in Base?

Actually, if modifying Base (or willing to commit type piracy), I believe an even simpler solution is the following:

!(f::typeof(in)) = βˆ‰
!(f::typeof(βˆ‰)) = in   # might as well while we are at it

This could perhaps be done just after !f::Function is defined in Base.

What would be the purpose of this?

1 Like

Good question. My goal has been to fill out all the methods of UniqueVectors with the most efficient versions possible. I noticed, though, that the !in method was not being called, despite me defining it; hence the question here. Examining this more, though, this method is actually no better than the fallback, so it’s completely unnecessary.

Then again, in Base it might be desirable to define an override method for findall for !in, just as there is currently one for in. I have no specific use for this method at the moment, but it seems useful and could be implemented more efficiently than the current fallback method (which performs linear search in the predicate for each element of the array being searched).

My understanding is that such a method could be defined already, dispatching on typeof(!in).

It is true that !!in would fail to call the method the method for in, and your proposal would remedy that. But instead, it would be better if !(!f) === f was implemented in general.

This does not work – see the original post for a minimal example.

Right, I missed the closure part.