Supporting syntax `x not in y` as alias for `!(x in y)`

One thing I like in Python is that they allow writing x not in y instead of !(x in y). To me this results in code that is much easier to read (obviously this is subjective).

I wonder if it would be possible to support this in Julia without introducing serious ambiguities to the language, and how much effort it would take.

3 Likes

A related issue: Add infix "!in" as synonym for ∉ ? · Issue #15353 · JuliaLang/julia · GitHub

6 Likes
6 Likes

This is one of the cases where I prefer the unicode a ∉ b over !(a in b).

My personal convention is to use ∈, ∋, and ∉ for inclusion tests, and in for iteration (which is a syntactic sugar for = anyhow).

11 Likes

(Note for new users: you can type by tab-completing \notin. This works in the Julia REPL and other interactive environments, and all major editors can also be configured to support these tab completions.)

5 Likes

Thanks for the pointers to the two existing issues. Though I’d consider !in strictly inferior to not in in terms of readability.

Also thanks to pointing out ∉ – I’ll make sure to use that for demos but I don’t feel comfortable using unicode like that in my actual code (of course that’s a “me” problem :wink: ).

Totally off-topic, but: for iteration, I don’t view in as syntactic sugar for =, but rather = as a horrible alternative syntax for in that is there to appease people coming from certain programming languages – it is IMHO utterly confusing for anyone else :-).

14 Likes

I agree with this.

9 Likes

That would be highly inconsistent, since ! is the negation operator. Are you suggesting replacing ! with not, so that, e.g. != becomes not == or not = ?

1 Like

No, I am not, and I think nothing I wrote suggests that? I talked about exactly one thing, “in”.

Though ironically what you wrote highlights one of the issues with the !in proposal – != does not mean not = after all. (That’s not to say I am opposed to it, but it just isn’t a perfect solution either)

2 Likes

In terms of consistency, I don’t think there should be both ! and not to mean logical negation. It was a genuine question (which seemed to follow logically), not an accusation.

I totally agree. The usage of != is very unfortunate, and is also a blocker for the issue I linked to further up. Having generic !<op> behavior would be great, but it’s too late to change !=. Still, in terms of consistency, !in is far preferable to not in, which I think would stick out like a sore syntactical thumb.

I think we could live with != and !== being special cases, and all other infix operators being negatable with the ! prefix.

7 Likes

We could also be more conservative and just allow !in and !isa, which seem like the least-objectionable and the most-beneficial infix operators to negate. I don’t see much of a need for !< or !! or !:<.

14 Likes

A blocking issue to general infix negation is that !(operator) is not an infix.

julia> typeof(!<)
ComposedFunction{typeof(!), typeof(<)}

julia> 1 (!<) 2
ERROR: ParseError:
1 (!<) 2
#└─────┘ ── extra tokens after end of expression

We could maybe special case (for example) !in to evaluate like (rather than ComposedFunction(!, in)) and to have infix parsing, but doing this for all infix operators seems excessive and like it would probably be breaking in some cases. Such handling would mean that disagreement could arise between (!in)(a,b) and !(in(a,b)) if a package overloads one but not the other.

It looks like the above poster beat me to part of this post.

2 Likes

!in is definitely the one I miss the most.

I agree, but it would be weird to allow !in but not !isa — the principle being to allow ! before any operator that is spelled like an ordinary function name.

3 Likes

I just meant, then the most important case would be covered, nothing against !isa

The relevance is that Python uses and, or, not where Julia uses &&, ||, !. Special-casing not in doesn’t make as much sense for that reason, !in is consistent with the rest of the language.

One can argue that and, or, not is easier to read, but Julia has already decided the question of how to spell logical operators.

5 Likes

I don’t think it’s breaking. Currently a !x b (with x an infix operator) gives a syntax error. We would just make it equivalent to (!x)(a, b) which already works for all infix operators AFAIK. Nothing else would change, for example the (silly) !< would still be a ComposedFunction{typeof(!), typeof(<)}, except that currently you have to write (!<)(1, 2) and with this change you could also write 1 !< 2

But then I admit I can’t see much use for it outside of !in. It makes no sense for most other ASCII operators and would probably need special casing for && and ||. It would make sense for many Unicode operators but these typically have a Unicode negation already, e.g. , , etc.

1 Like

Yeah I think the sane alternative would be notin rather than not in.

2 Likes

I would read !in as “not in” in any of these spellings, so I favor !in as the most consistent choice. !isa is kind of goofy but isn'ta isn’t parsable and isnta is illegible, isnota isnota much better choice, so I’d take !isa there as well, although I’d probably stick with !(T isa U) for aesthetic reasons.

Actually, isnta is growing on me. T isnta U isn’t proper English but nothing says it has to be.

4 Likes