! for infix operators

question

#1

From the docs:

Predicate function negation: when the argument of ! is a function, it returns a function which computes the boolean negation of f.

Hence, !iseven is a function that returns true if the argument is not even. I think it would be useful to generalize this behavior for infix operators, like ==, , etc. Currently !== has its own definition, but !≈ is undefined. If ! worked automatically for infix comparison operators, !≈ would work.


#2

Try tab completing \napprox for negating isapprox. If all of the Boolean binary operators already have negated forms, I don’t see much to be gained from !


#3

Well, the same could be said about having !fun define a new function that negates the result of fun; you could just define !fun directly. Still people find the automatic negation by ! useful.


#4

I think that !≈ is already allowed, it is just not an infix operator anymore.

julia> f = !≈
(::#57) (generic function with 1 method)

julia> f(1,2)
true

julia> f(1,1)
false

I guess it could be parsed and lowered as you suggest, but the parser would have to special case !=.


#5

The difference is that there is only a small set of boolean infix operators, and all the ones defined in base already have negated forms.


#6

Actually what I was thinking was having ! behave the same for infix operators as it does for ordinary functions, in general, not just for .


#7

Maybe I was not clear: I meant parsed as it would be for ordinary functions (eg as now), but with the result allowed in an infix position.

However, I agree with @stevengj: given that infix ops already have a negated version which is more compact, I don’t see the pressing need for this. Presumably people are using infix for brevity, so the shorter the better. But perhaps you could open an issue so that this is given due consideration in the post-1.0 era.


#8

I miss this:

julia> 2 !in [3, 4]
ERROR: syntax: extra token "!" after end of expression

This is possible:

julia> 2 ∉ [3, 4]
true

but it’s a bit unsymmetrical and unsatisfactory if you normally use in rather than .


#9

Also, what if I define my own boolean operator? Would be nice to be able to get automatic negation with !<op>.


#10

I don’t think you can define your own infix boolean operator


#11

#12

You can, of course, use one of the many Unicode comparison operators that are parsed as infix operators by Julia but which don’t have a built-in definition in Base, like . But for these it would typically be more natural to define e.g. ≹(x,y) = !(x ≷ y) using the corresponding Unicode negated operator.

On the other hand, there are some oddball ones like that don’t seem to have negated versions in Unicode.


#13

Surely, any infix operator can be boolean if I say so:

julia> Base.:+(a::String, b::String) = first(a) in b

julia> "hello" + "ahh"
true

julia> "hello" !+ "ab"
ERROR: cannot document the following expression:

!(+"ab")

julia> !+("hello", "ab")
true

#14

But honestly, my main point is about !in. If my code has lots of

if a in A

in it, but then I want

if b !in B

I don’t think !(b in B) or b ∉ B is completely satisfactory. So, at least !in would be appreciated.

Edit: I might also like to do SomeType !<: Number, or x !< y (to perhaps make a point, while also avoiding unicode). Etc., etc., ad nauseam.


#15

What’s the problem with (tab-completed from \notin)?

… or x !< y (to perhaps make a point, while also avoiding unicode). Etc., etc., ad nauseam.

x !< y is also known as x >= y (or x ≥ y), at least for non-NaN values.


#16

True, and yet these also exist in unicode in negated form: , , etc


#17

A few things:

  • It does not look nice to mix in and in the same code
  • I may be conservative about using unicode symbols
  • Many unicode symbols don’t look very nice in my preferred coding font, typically they are too small and hard to read compared to the surrounding code
  • Some unicode symbols may not have negated forms at all.

I may want to make a particular point, e.g. that x !< y is an unusual case, and want it to be visually distinctive.

I’m a bit surprised that the preference seems to be relying on the existence of special unicode negated versions, rather than relying on simple composition.


#18

Compositions that require changes to the parser are always going to get some pushback — parser changes require a lot of care because there is so much room for unintended consequences.


#19

That is of course a valid argument.

I have opened an issue here https://github.com/JuliaLang/julia/issues/25512 requesting this feature, then I guess we’ll see. This is hardly a critical feature, so the core devs can take their time to consider it.