JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.88k stars 5.49k forks source link

Document literal_pow #28685

Open laborg opened 6 years ago

laborg commented 6 years ago

As discussed in https://discourse.julialang.org/t/confusing-difference-literal-vs-variable/13515/5 it would be good if this is documented somewhere. The explanation of @StefanKarpinski in this thread will be helpful:

This was a controversial change and there are still many people who are not entirely comfortable with it. The starting point is that people do not really often expect or want x^2 and x^-1 to be pow(x, 2) and pow(x, -1), respectively. Rather, people want x^2 to be syntax for xx. The latter can generally be implemented much more efficiently than calling a general power function. With sufficiently clever optimizations (constant propagation + power reduction), one can potentailly optimize pow(x, 2) into xx but it would be even better if we didn’t have to do such a clever optimization in the first place. It’s been a fairly common and successful strategy in the design of Julia to arrange things so that you can get great performance in a straightforward way without need for clever optimizations instead of trying to make the optimizers smarter. So what this design does is it causes x^n where n is a literal integer value to call Base.literal_pow(x, Val(n)), which allows us to specialize the syntax on individual literal values like 2 or -1. This allow us to make x^2 actually mean x*x instead of needing to try to optimize it to that. It also allows us to make negative literal exponents work without introducing a type instability in the general ^ function. And indeed, we used to get regular complaints from new users that 2^-1 doesn’t return 0.5 as they would expect, instead giving them a domain error because of the negative exponent. There are good reasons for it but users don’t care about involved language design reasons, they just want it to work. A way to think about this is that ^2 is its own operator, as is ^3 and ^-1, and so on. Hopefully that helps.

24240

laborg commented 6 years ago

Mhm. It is basically documented in ^:

If y is an Int literal (e.g. 2 in x^2 or -3 in x^-3), the Julia code x^y is transformed by the compiler to Base.literal_pow(^, x, Val(y)), to enable compile-time specialization on the value of the exponent. (As a default fallback we have Base.literal_pow(^, x, Val(y)) = ^(x,y), where usually ^ == Base.^ unless ^ has been defined in the calling namespace.)

But from that I think it's not clear that this compile-time specialization results in unexpected behaviour (see discourse thread).

fredrikekre commented 6 years ago

Maybe we can add it as a FAQ?

laborg commented 6 years ago

As a naive user I expected to find something in the Mathematical Operations and Elementary Functions - Arithmetic Operators section of the manual. I think this is a section everybody new to Julia will read at least once, so it might be a good place to raise awareness and point to further information.