Hello. I’ve spent some time reading about the reasons behind why Julia deals with negative exponents the way it does and I’m not interested in resurrecting that debate. I’m working on a script and I’ve run into a problem that boils down to the following:
-1.5 ^ -1.5 # Works!
b = -1.5
b ^ b # Doesn't work! :(
# Why? Because:
(-1.5) ^ (-1.5) # also doesn't work while
- (1.5) ^ (-1.5) # works, and is what the above is evaluated as.
How can I get Julia to accept taking a variable with a negative base to a negative exponent?
Are there any other programming languages that give ^ higher precedence than unary - though?
It seems like something rather ripe for confusion and hard to find bugs.
Prolog is tricky: the arithmetic expression -2 ** 2 evaluates as 4.0 even though exponentiation does have precedence over negation. (I’m not sure why it goes to a float. It’s been a while since I knew these things.)
That’s because in Prolog the minus sign in -2 is not the negation operator but a part of literal syntax.
In the arithmetic expression -B ** 2, where the base is a variable, the minus sign is an operator. That expression is parsed as -(B ** 2) and maybe should not be spaced the way I did.
julia> dump(parse("-2.0 * u"))
Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol *
2: Float64 -2.0
3: Symbol u
typ: Any
but with ^, it is parsed differently, i.e.:
julia> dump(parse("-2.0 ^ u"))
Expr
head: Symbol call
args: Array{Any}((2,))
1: Symbol -
2: Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol ^
2: Float64 2.0
3: Symbol u
typ: Any
typ: Any
This sort of inconsistency, and having special handling in the parser for ^ vs. *, just seems wrong to me.
I think it’s just a peephole optimization built into the Julia parser.
The parses of "-2 * 2" and "-u * w", resp. "-2^2" and "-u^w" are consistent with exponentiation having precedence over unary minus, and unary minus over multiplication.
That doesn’t fit well with the idea that one can have different meanings for the operators, depending on what types they are applied to (not that that’s a good thing - I’d prefer that Julia eliminated the type punning for AbstractString on * and ^).
IIRC, didn’t Fortress have a way of giving a warning or error when the spacing indicated that the programmer intention was clearly at odds with what the compiler would do, in this sort of case?
There seems to be an actual inconsistency (in the REPL in Julia 0.5.0) with what I guessed to be a peepholing in the parser if a program overrides the meaning of unary minus.
julia> import Base.-
julia> function (-)(x::Int) 3 end
- (generic function with 191 methods)
julia> -2, -(2), - 2
(-2,3,3)
julia> u = 2 ; -u, -(u), - u
(3,3,3)
But is it ever a good idea to override Base methods of unary minus?
By the way, while a macro could undo the parse-time analysis and reanalyze a negative number as a negation of a number, there is no way to recover certain occurrences of a unary plus from the parse tree. Those are truly gone.
I wouldn’t worry about either of these. They affect some built-in literal types only, and those I think are best left to Julia.