# \`in(x, y)\` and \`y in x\` behave differently?

**URL:** https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965
**Category:** General Usage
**Tags:** question
**Created:** [April 15, 2024, 1:46pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965 "2024-04-15T13:46:38Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)
#### Post date: [April 15, 2024, 1:46pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/1 "2024-04-15T13:46:38Z")

</div>

I made a dummy range

```julia
struct MyRange
    starting::Int
    ending::Int
end

```

for which I only care to check whether integers are contained there.  
Consequently I implemented the `Base.in`

```julia
function Base.in(r::MyRange, i::Int)
    return r.starting <= i <= r.ending
end

```

Testing the implementation everything works as expected

```julia
julia> r = MyRange(4, 7)
MyRange(4, 7)

julia> in(r, 5) # works
true

```

But if I use the binary operator syntax it errors

```julia
julia> 5 in r # errors
ERROR: MethodError: no method matching iterate(::MyRange)

Closest candidates are:
  iterate(::Base.AsyncGenerator, ::Base.AsyncGeneratorState)
   @ Base asyncmap.jl:362
  iterate(::Base.AsyncGenerator)
   @ Base asyncmap.jl:362
  iterate(::Pkg.Registry.RegistryInstance)
   @ Pkg ~/.julia/juliaup/julia-1.10.2+0.x64.linux.gnu/share/julia/stdlib/v1.10/Pkg/src/Registry/registry_instance.jl:
455
  ...

Stacktrace:
 [1] in(x::Int64, itr::MyRange)
   @ Base ./operators.jl:1292
 [2] top-level scope
   @ REPL[32]:1

```

I get it that I need to implement an iterator for that, but I just don’t want to.

For the sake of completeness the example works if I add the following methods but I find them redundant for my case.

```julia
function Base.iterate(r::MyRange)
    return (r.starting, 1)
end

function Base.iterate(r::MyRange, i::Int)
    i >= r.ending && return nothing
    return (r.starting + i, i+1)
end

```

I really thought that using any binary operator (say `ˣ`) as `ˣ(a,b)` or `a ˣ b` is indistinguishable. It seems that’s not the case. Is `in` a corner case because it’s not a commutative operator? But still, I feel that if `Base.in(a, b)` is implemented the `b in a` should bypass anything else and default to that.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 15, 2024, 1:49pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/2 "2024-04-15T13:49:54Z")

</div>

> [@filchristou](#):
>
> Consequently I implemented the `Base.in`
> 
> ```julia
> function Base.in(r::MyRange, i::Int)
> return r.starting <= i <= r.ending
> end
> 
> ```

Your arguments are in the wrong order. `x in y` is equivalent to `in(x, y)`, not `in(y, x)`.

This wasn’t very explicit in the [`in` docstring](https://docs.julialang.org/en/v1/base/collections/#Base.in), so I submitted a pull request: [note infix syntax for "in" and "∈" by stevengj · Pull Request #54091 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/54091)

---

<div class="post-metadata">

### Author: ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)
#### Post date: [April 15, 2024, 7:56pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/3 "2024-04-15T19:56:05Z")

</div>

Julia is somewhat consistent in the order of these arguments, also for similar functions: When writing a function call, the correct order of arguments is what would be natural if the function could be used infix: `contains`, `occursin`, `startswith`, `endswitch`, etc.

It’s `contains(haystack, needle)`, since `haystack contains needle` would be the natural infix version.

Which is, in fact, another argument that all these functions (and others, maybe even _all_ two-arg functions) _should_ be available with an infix syntax. It quite boggles my mind that this idea never gained much traction in Julia. When it comes to readability, there are still a few slices that Julia could take of the Python cake.

---

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [April 15, 2024, 8:00pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/4 "2024-04-15T20:00:07Z")

</div>

Personally I don’t like infix `in` because it’s different from almost everything else in the language.

* * *

In haskell, you can write any function infix by surrounding it in backticks

```julia
> f x y = x + y
> f 1 2
3
> 1 `f` 2
3

```

---

<div class="post-metadata">

### Author: ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)
#### Post date: [April 15, 2024, 8:19pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/5 "2024-04-15T20:19:36Z")

</div>

> [@jar1](#):
>
> I don’t like infix `in` because it’s different from almost everything else in the language.

I don’t like that everything else in the language is different from infix-`in`. So I think we’re actually in agreement 😉

---

<div class="post-metadata">

### Author: ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)
#### Post date: [April 15, 2024, 10:07pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/6 "2024-04-15T22:07:15Z")

</div>

> [@goerz](#):
>
> Which is, in fact, another argument that all these functions (and others, maybe even _all_ two-arg functions) _should_ be available with an infix syntax. It quite boggles my mind that this idea never gained much traction in Julia. When it comes to readability, there are still a few slices that Julia could take of the Python cake.

Quite aside from the parsing challenges this would entail, would this not mean that every two-arg function would need to be assigned a precedence? There’s no mechanism for that presently, no way of going back and assigning them to all the two-arg functions which currently exist, and this would have to be conveyed to the parser, which poses serious problems with using a function so-defined in the same module as it’s defined in.

When I say “parsing challenges” that isn’t even what I mean. I don’t think it would be decidable.

```julia
julia> a, b, c = 1, 2, 3
(1, 2, 3)

julia> [a b c]
1×3 Matrix{Int64}:
 1 2 3

julia> [a < c]
1-element Vector{Bool}:
 1

```

What if `b` were a two-arg function? What if the matrix were in a loop, and `b` changed from an `int` to a function?

```julia
julia> a, b, c = 1, <, 3
(1, <, 3)

julia> [a b c]
1×3 Matrix{Any}:
 1 < 3

julia> b(a, c)
true

```

Infix is special because the parser has to know about it.

Yes, there are languages which let you specify a custom operator and define a precedence for it. They usually restrict this to certain characters, without overlap with normal symbolic names, though exceptions exist, Prolog being one. I’m glad I never wrote a parser for any of them, and writing parsers is what I do.

---

<div class="post-metadata">

### Author: ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)
#### Post date: [April 15, 2024, 11:09pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/7 "2024-04-15T23:09:35Z")

</div>

> [@mnemnion](#):
>
> Quite aside from the parsing challenges this would entail, would this not mean that every two-arg function would need to be assigned a precedence?

Can’t they all have equal (and low) precedence? That is, left to right?

> [@mnemnion](#):
>
> ```julia
> julia> [a < c]
> 1-element Vector{Bool}:
> 1
> 
> ```

I’m guessing the inside of array constructors is already a somewhat special context, and at least in that context, it would seem pretty feasible if symbols have higher precedence than infix functions. That is, `[a contains b]` has three elements (which it currently does), and `[(a contains b)]` contains 1 element.

If wouldn’t even mind some pretty severe restrictions, like requiring that an infix functions have to return booleans and/or that they have to be enclosed in parentheses to be a complete expression. Wouldn’t “anything that might be ambiguous needs parentheses” be pretty workable?

I’m not saying it wouldn’t make the parser more difficult to write, but it’s hard for me to imagine that `if (a contains b) then`, or `contained = (a contains b)` would be impossible to support if there was a will.

Right now, `(x f y)` is not a valid Julia expression, and I don’t really see a reason that that couldn’t lower to `f(x, y)`. Although there are some pretty long threads about this topic both on Discourse and Github, and I’m sure there was some objection to `(x f y)`.

---

<div class="post-metadata">

### Author: ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)
#### Post date: [April 15, 2024, 11:45pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/8 "2024-04-15T23:45:57Z")

</div>

> [@goerz](#):
>
> Can’t they all have equal (and low) precedence? That is, left to right?

`in` and `isa` both have 7, so that isn’t a non-starter…

> [@goerz](#):
>
> I’m guessing the inside of array constructors is already a somewhat special context, and at least in that context, it would seem pretty feasible if symbols have higher precedence than infix functions. That is, `[a contains b]` has three elements (which it currently does), and `[(a contains b)]` contains 1 element.

This, I don’t like. Now there are real infix and pseudo-infix functions:

```julia
julia> [1 in 1:5]
1-element Vector{Bool}:
 1

```

My objection is more like the antipathy some people feel for `|>` (which I like): there doesn’t _need_ to be two ways to call a function (this would make three!), and it adds an edge case to the language where there doesn’t need to be one. If you get used to writing `a contains b`, and write `[is_done has_flag "foo" contains char]`, that’s a bug which never had to happen. `in` is a load-bearing part of the language, but I wouldn’t miss infix `isa` if we didn’t happen to have it.

Here’s another “need to use parens” albeit a bit contrived:

```julia
julia> begin
         5
         <
         7
       end
7

julia> foo, bar, baz = :foo, :bar, :baz
(:foo, :bar, :baz)

julia> begin
         foo
         bar
         baz
       end
:baz

```

TL;DR, it can’t be successfully parsed, the parser simply has to know all the infix operators, or you have fake ones which only work sometimes.

```julia
julia> begin
         bux = 5
         >
         quux = 3
       end
3

```

It opens a real can of worms, is what I’m saying.

I’m fine writing `if contains(needle, haystack)`, and consider this: at precedence 7, which, given our two letter-infix operators both have 7 it would be strange to pick an even lower number, `if 7 > 5 min 6` is a MethodError, and `if 5 min 6 < 7` is `true`.

I grant you that these problems could be solved with enough parentheses. I just don’t think it’s a good idea.

---

<div class="post-metadata">

### Author: ![alfaromartino](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alfaromartino/32/52986_2.png) [@alfaromartino](https://discourse.julialang.org/u/alfaromartino)
#### Post date: [April 15, 2024, 11:53pm UTC](https://discourse.julialang.org/t/in-x-y-and-y-in-x-behave-differently/112965/9 "2024-04-15T23:53:39Z")

</div>

If you tend to forget about it, you also have a built-in curried version. This also avoids the need of `Ref`.

```julia
x = [2, 4, 6]
list = [1, 2, 3]

in(list).(x)

```
