★ is not an operator

question

#1

Just stumbled about the wish to use ★ as an operator. That does not work

julia> ★(a, b) = a + b
★ (generic function with 1 method)
julia> 1 ★ 3
ERROR: syntax: extra token "★" after end of expression

when looking into https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm it appears that ★ is not found when searched for.
Was it forgotten?

Anyone knowing what goes on here?
thanks a lot


#2

You’re trying to use a function as an infix operator, that doesn’t work. If you call it normally, it will work as expected.

The reason e.g. a + b can be used as an infix is because that is special cased at lowering and actually transforms into +(a,b). See also the docs, Operators Are Functions.


#3

I believe the file you linked to is the correct one – the list of symbols which will be parsed as infix multiplication (like *) is long, but doesn’t include . I don’t know of a good reason for that, it could be just an oversight?

* / ÷ % & ⋅ ∘ × \ ∩ ∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓ ∗ ∙ ∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰ ⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻ ⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘ ⩚ ⩜ ⩞ ⩟ ⩠ ⫛ ⊍ ▷ ⨝ ⟕ ⟖ ⟗

Note that it does include , there’s a chance these were judged to be too similar? Both are things you can type:

help?> ★
"★" can be typed by \bigstar<tab>

help?> ⋆
"⋆" can be typed by \star<tab>

#4

If you don’t mind me asking, what operation should ★ be parsed as anyway? In my mind it only makes sense to parse it as infix if there exists some already defined function for it to be called as. In the example by @schlichtanders, ★ is a user defined function, so the parser can’t really know about it beforehand and parse it as infix.

Note that Σ (\Sigma) is also possible to type, as are a lot of LaTeX symbols, but that doesn’t necessarily mean they represent something useful out of the box:

help?> Σ                    
"Σ" can be typed by \Sigma<tab>

search:
Couldn't find Σ
Perhaps you meant [...]

 No documentation found.
 
 Binding Σ does not exist. 

See here for more info:

In the Julia REPL and several other Julia editing environments, you can type many Unicode math symbols by typing the backslashed LaTeX symbol name followed by tab.


#5

+ is also a “user defined function” with one definition at

As already shown, there are also many symbols that parse as infix without having a meaning already.


#6

The ★ operator is actually a unary operator in mathematics, and not a binary infix operator

This is a method which I intend to implement for Grassmann.jl


#7

You are free to define say Σ(x) = sum(x), but can never write 2 Σ 3 because sigma is parsed as an ordinary letter, not an infix operator. It’s pretty neat that lots of symbols are parsed as operators, precisely so that you can later define them as whatever special kind of multiplication your problem needs.

Good point @chakravala that it’s useful for some star-like symbols not to be infix. Ideally you’d like the one you use for hodge to be parsed as unary – are there any such user-definable symbols? E.g. works infix like - but not alone:

julia> ⊖3
ERROR: syntax: "⊖" is not a unary operator

#8

It has several uses in mathematics and various scientific disciplines. Here’s an example of a binary star operator, from mathematics:


#9

I think it is fine to wait a bit before defining operators which don’t have a widely accepted arity.

Also, there are plenty of Unicode operators already, so unless one insists on using a particular one, finding a substitute should not be a problem.


#10

Operators like + and - can be used as both binary and unary

julia> +1, -1, 1+1, 1-1
(1, -1, 2, 0)

So I don’t see any issue with -arity. The main mystery is probably the precedence of ★ operation?


#11

Ah right, my mistake – binary parsing is no bar to also having unary meaning.

I guess you want precedence slightly above *, so that you can write 2★ω? I see that is an ordinary letter now, thus parsing ∂V as ∂(V) would be a breaking change… not to mention !


#12

Unary and binary + are different operators with the same symbol, they are definitely not the same operator and get lowered to different functions.

As I said before, a + b gets lowered to +(a,b):

julia> @code_lowered 1 + 2
CodeInfo(
   1 ─ %1 = (Base.add_int)(x, y)
   └──      return %1
)

julia> @code_lowered -(1)                                                                                               
CodeInfo(
    1 ─ %1 = (Base.neg_int)(x)
    └──      return %1
)

EDIT: In the case of -1, that’s actually a negative integer literal and doesn’t get lowered to anything:

julia> @code_lowered -1                                                                                  
ERROR: expression is not a function call or symbol                                                       
Stacktrace:                                                                                               
  [1] error(::String) at ./error.jl:33                                                                     
  [2] top-level scope at [...]

#13

If you overload - then the unary form does use that function, although it seems to be inlined already in what @code_lowered shows:

julia> struct Z z end
julia> Base.:-(z::Z) = println("minus ",z.z)
julia> @code_lowered -Z(3)
CodeInfo(
1 ─ %1 = (Base.getproperty)(z, :z)
│   %2 = (Main.println)("minus ", %1)
└──      return %2
)



#14

Both the unary and binary operation are called from the same name, +

It may get lowered to a different call, but the + name is a single name with both unary and n-ary dispatch.

julia> :(+x) |> dump
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Symbol +
    2: Symbol x

julia> :(x+y) |> dump
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol +
    2: Symbol x
    3: Symbol y

As you can see, a unary method is listed as the [3] entry.

julia> methods(+)
# 163 methods for generic function "+":
[1] +(x::Bool, z::Complex{Bool}) in Base at complex.jl:277
[2] +(x::Bool, y::Bool) in Base at bool.jl:104
[3] +(x::Bool) in Base at bool.jl:101
...

#15

This is a different stage in the process though, long after parsing - my whole point is that this works because + can be parsed as infix, which does not apply to as it’s not in the list you linked above.

julia> f(x,y) = x + y
f (generic function with 1 method)

julia> :(x f y) |> dump
ERROR: syntax: missing comma or ) in argument list

julia> :(x + y) |> dump
Expr
    head: Symbol call
    args: Array{Any}((3,))
        1: Symbol +
        2: Symbol x
        3: Symbol y                                   

That’s the difference between the infix operator (which the parser is aware of) and a function masquerading as that same infix operator.


It seems this topic has changed from “why is ★ not an operator/can’t be used infix” to “let’s add ★ to the list of recognized infix operators” for which I don’t yet see a compelling reason. Is there a case such that both * and are needed and none of the already existing unicode characters can be used?


#16

Yes, there is a case, in my package Grassmann.jl there is the * product for a geometric product and I intend to use for the Hodge star dual operation. These are two entirely separate operations both within the same package.

Whether it’s on the list or not is not that important to me, but I don’t see any reason against it.


#17

★ is U+2605, “black star”, in Unicode category So (Symbol, other).

For the most part (with the exception of some arrows), Julia only parses a subset of category Sm (Symbol, math) as infix operators.

In particular, you should look at U+22C6 (“star operator”), typed by tab-completing \star in the REPL, which is in category Sm and is parsed as an infix operator:

julia> ⋆(x,y) = 2x+y
⋆ (generic function with 1 method)

julia> 3 ⋆ 4
10

(Unfortunately, in many fonts, is shown rather small.)


#18

Thanks, that settles where the list came from.

And answering my own question by scrolling down, the list of unary operators is this: + - ! ~ ¬ √ ∛ ∜, of which ¬ and aren’t already defined.