Skip to content

Commit b51d41a

Browse files
moblestevengjfingolfin
authored
Improve documentation of operators (#60286)
I've always found the documentation of operators a little disjointed and incomplete; this PR aims to improve the situation. - Add missing items to the precedence table - Adjoint operator goes after `::` and before exponentiation - Juxtaposition of numeric literals goes after unary operators and before bitshifts - Arrows go between `||` and `?` - New footnote explains exceptions to exponentiation precedence - New footnote explains non-associativity of comparisons, but notes chaining - Add more complete lists of operators - Include *all* operators defined in Base - Include operators that are available but not defined in Base, set off by parentheses - Operator suffixes - Note that new operators can be defined with suffixes - Explain what those prefixes are - Show an example - Provide some links between disjoint pages - Link from [Manual > Variables](https://docs.julialang.org/en/v1/manual/variables/#man-allowed-variable-names) to operator section - Link from [Manual > Integers and Floating-Point Numbers](https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/#Integers-and-Floating-Point-Numbers) to operator section - Link from [Manual > Functions](https://docs.julialang.org/en/v1/manual/functions/#man-functions) to operator section - Link back to functions page when noting that operators are functions. --------- Co-authored-by: Steven G. Johnson <stevenj@mit.edu> Co-authored-by: Max Horn <max@quendi.de>
1 parent 2bce340 commit b51d41a

4 files changed

Lines changed: 85 additions & 29 deletions

File tree

doc/src/manual/functions.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,11 @@ alone is a matter of coding style.
240240

241241
## Operators Are Functions
242242

243-
In Julia, most operators are just functions with support for special syntax. (The exceptions are
244-
operators with special evaluation semantics like `&&` and `||`. These operators cannot be functions
245-
since [Short-Circuit Evaluation](@ref) requires that their operands are not evaluated before evaluation
246-
of the operator.) Accordingly, you can also apply them using parenthesized argument lists, just
247-
as you would any other function:
243+
In Julia, most [operators](@ref Operator-Precedence-and-Associativity) are just functions with support
244+
for special syntax. (The exceptions are operators with special evaluation semantics like `&&` and `||`.
245+
These operators cannot be functions since [Short-Circuit Evaluation](@ref) requires that their operands
246+
are not evaluated before evaluation of the operator.) Accordingly, you can also apply them using
247+
parenthesized argument lists, just as you would any other function:
248248

249249
```jldoctest
250250
julia> 1 + 2 + 3

doc/src/manual/integers-and-floating-point-numbers.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,8 +683,8 @@ julia> 2^2x
683683
64
684684
```
685685

686-
The precedence of numeric literal coefficients is slightly lower than that of
687-
unary operators such as negation.
686+
The [precedence](@ref Operator-Precedence-and-Associativity) of numeric literal
687+
coefficients is slightly lower than that of unary operators such as negation.
688688
So `-2x` is parsed as `(-2) * x` and `√2x` is parsed as `(√2) * x`.
689689
However, numeric literal coefficients parse similarly to unary operators when
690690
combined with exponentiation.

doc/src/manual/mathematical-operations.md

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -398,36 +398,90 @@ e.g. `sin.(A)` will compute the sine of each element of an array `A`.
398398

399399
## Operator Precedence and Associativity
400400

401-
Julia applies the following order and associativity of operations, from highest precedence to lowest:
401+
Julia recognizes a large list of characters (or strings of a few characters in some cases) as
402+
operators, each with a defined precedence and associativity. When an expression contains multiple
403+
operators, the precedence and associativity determine how the expression is parsed into function
404+
calls — though parentheses can always be used to explicitly specify the desired order of
405+
operations.
406+
407+
Most of these [operators are functions](@ref Operators-Are-Functions).[^1] They can be used with
408+
either functional notation (e.g., `+(a, b)`) or "infix" notation (e.g., `a + b`) — the parser
409+
essentially rewrites infix expressions as function calls. In functional notation, the grouping of
410+
operations is explicit from the parentheses, so the expression is parsed unambiguously. When
411+
infix notation is used with more than one operator in an expression and parentheses do not
412+
disambiguate the order, precedence and associativity rules determine how the expression is parsed.
413+
414+
[^1]:
415+
Some operators are parsed specially: `&& || = += -= *= /= //= \= ^= ÷= %= <<= >>= >>>= |= &=
416+
⊻= := $= . ... -> $ & ::`, as well as the ternary conditional `a ? b : c`.
417+
418+
In an expression with different operators, *precedence* determines the order. For example, `*`
419+
has higher precedence than `+` when used as binary operators, so `1 + 2 * 3` is parsed as
420+
`1 + (2 * 3)`. In an expression with the same operator used more than once, *associativity*
421+
determines the order. For example, with a left-associative operator `a ⊗ₗ b ⊗ₗ c` is parsed as
422+
`(a ⊗ₗ b) ⊗ₗ c`; with a right-associative operator `a ⊗ᵣ b ⊗ᵣ c` is parsed as `a ⊗ᵣ (b ⊗ᵣ c)`.
423+
424+
Some operators are neither left- nor right-associative. As discussed [above](@ref
425+
Chaining-comparisons), comparison operators such as `<` and `==` are *chaining* operators, with no
426+
fixed order of evaluation. Another such group is the [*varargs*](@ref Varargs-Functions)
427+
operators `+`, `++`, and `*` (but not other addition or multiplication operators). These are
428+
parsed as varargs calls when chained, rather than nested binary calls: `a + b + c` is parsed as
429+
`+(a, b, c)` and `a*b*c` is parsed as `*(a, b, c)`. The `++` operator is also parsed in this
430+
way, but note that it has no methods defined in `Base`. Also note that juxtaposition of numeric
431+
literal coefficients to denote multiplication — like `2x` to mean `2*x` — is more of a syntactic
432+
form than an operator. Describing its associativity doesn't make sense, except to state the
433+
obvious point that `24x` means `24*x` rather than `2*(4*x)` or `(2*4)*x`.
434+
435+
The following table lists Julia's operators, from highest precedence to lowest. Those listed
436+
outside of parentheses are already defined in the `Base` module; those listed inside parentheses
437+
are not currently defined in `Base`, but are available to be defined by standard libraries,
438+
packages, or user code. For example, `` and `×` are defined in the standard library's
439+
`LinearAlgebra` package. Some of the latter lists are incomplete; for a complete listing of
440+
*every* Julia operator and its precedence, see the top of this file:
441+
[`src/julia-parser.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm).
402442

403443
| Category | Operators | Associativity |
404444
|:-------------- |:------------------------------------------------------------------------------------------------- |:-------------------------- |
405-
| Syntax | `.` followed by `::` | Left |
406-
| Exponentiation | `^` | Right |
407-
| Unary | `+ - ! ~ ¬ √ ∛ ∜ ⋆ ± ∓ <: >:` | Right[^1] |
445+
| Syntax | `.` followed by `::` followed by `'` | Left |
446+
| Exponentiation | `^` (`↑ ↓ ⇵ ⟰ ⟱ ⤈ ⤉ ⤊ ⤋ ⤒ ⤓`, etc.) | Right[^2] |
447+
| Unary | `+ - ! ~ √ ∛ ∜ <: >:` (`¬ ⋆ ± ∓`) | Right[^3] |
448+
| Juxtaposition | Implicit multiplication by numeric literal coefficients; e.g., `2x` is parsed as `2*x` | Not applicable |
408449
| Bitshifts | `<< >> >>>` | Left |
409450
| Fractions | `//` | Left |
410-
| Multiplication | `* / % & \ ÷` | Left[^2] |
411-
| Addition | `+ - \| ` | Left[^2] |
412-
| Syntax | `: ..` | Left |
451+
| Multiplication | `* / ÷ % & ∘ \ ∩ ⊼` (`⋅ × ⋆ ⊗ ⊘ ⊠ ⊡ ⊓ ∧`, etc.) | Left[^4] |
452+
| Addition | `+ - \| ∪ ⊻ ⊽` (`++ ± ∓ ⊕ ⊖ ⊞ ⊟ ⊔ ∨`, etc.) | Left[^4] |
453+
| Syntax | `:` (`.. … ⁝ ⋮ ⋱ ⋰ ⋯`) | Left |
413454
| Syntax | `\|>` | Left |
414455
| Syntax | `<\|` | Right |
415-
| Comparisons | `> < >= <= == === != !== <:` | Non-associative |
416-
| Control flow | `&&` followed by `\|\|` followed by `?` | Right |
456+
| Comparisons | `in isa > < >= ≥ <= ≤ == === ≡ != ≠ !== ≢ ∈ ∉ ∋ ∌ ⊆ ⊈ ⊊ ≈ ≉ ⊇ ⊉ ⊋ <: >:` (`⊂ ⊄ ∝ ∥`, etc.) | Chaining[^5] |
457+
| Control flow | `&&` followed by `\|\|` | Right |
458+
| Arrows | (`← → ↔ ↚ ↛ ↢ ↣ ↦ ↤ ↮ ⇎ ⇍ ⇏ ⇐ ⇒ ⇔`, etc.) | Right |
459+
| Control flow | `?` | Right |
417460
| Pair | `=>` | Right |
418-
| Assignments | `= += -= *= /= //= \= ^= ÷= %= \|= &= ⊻= <<= >>= >>>=` | Right |
461+
| Assignments | `= += -= *= /= //= \= ^= ÷= %= <<= >>= >>>= \|= &= ⊻= ~` (`≔ ⩴ ≕ :=`) | Right |
419462

420-
[^1]:
421-
The unary operators `+` and `-` require explicit parentheses around their argument to disambiguate them from the operator `++`, etc. Other compositions of unary operators are parsed with right-associativity, e. g., `√√-a` as `√(√(-a))`.
422463
[^2]:
423-
The operators `+`, `++` and `*` are non-associative. `a + b + c` is parsed as `+(a, b, c)` not `+(+(a, b),
424-
c)`. However, the fallback methods for `+(a, b, c, d...)` and `*(a, b, c, d...)` both default to left-associative evaluation.
425-
426-
For a complete list of *every* Julia operator's precedence, see the top of this file:
427-
[`src/julia-parser.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm). Note that some of the operators there are not defined
428-
in the `Base` module but may be given definitions by standard libraries, packages or user code.
429-
430-
You can also find the numerical precedence for any given operator via the built-in function `Base.operator_precedence`, where higher numbers take precedence:
464+
Unary operators and juxtaposition of numeric literals take precedence over `^` only *within the exponent*. For example, `2^-3`, `x^√2`, and `2^3x` are parsed as `2^(-3)`, `x^(√2)`, and `2^(3*x)`; whereas `-2^3`, `√x^2`, `2^3*x`, and `2x^3` are parsed as `-(2^3)`, `√(x^2)`, `(2^3)*x`, and `2*(x^3)`.
465+
[^3]:
466+
Note that most unary operators can be composed, except `++` which is a distinct *binary* operator, and `--` which produces a `ParseError`. Other compositions of unary operators are parsed with right-associativity — e.g., `√√-a` as `√(√(-a))`.
467+
[^4]:
468+
The operators `+`, `++` and `*` are parsed differently. For example, `a + b + c` is parsed as `+(a, b, c)` not `+(+(a, b),c)`. However, the fallback methods for `+(a, b, c, d...)` and `*(a, b, c, d...)` both default to left-associative evaluation. Note that `++` is not defined in `Base`, but is parsed in the same way.
469+
[^5]:
470+
Comparisons can be [chained](@ref "Chaining comparisons"). For example, `a < b < c` is essentially the same as `a < b && b < c`. However, the order of evaluation is undefined.
471+
472+
It is also possible to define additional operators by appending suffixes to most of the binary operators. The valid
473+
suffixes include the Unicode combining characters, along with the subscripts, superscripts, and various primes
474+
(`′ ″ ‴ ⁗ ‵ ‶ ‷`) listed in
475+
[`src/flisp/julia_opsuffs.h`](https://github.com/JuliaLang/julia/blob/master/src/flisp/julia_opsuffs.h). The
476+
resulting operators can be used with either functional or infix notation, and have the same precedence and
477+
associativity as the base operator. For example, `⋆̂ᵝ₁′` could be defined as a function, and used as an infix operator
478+
with the same precedence and associativity as `` and `*`. However, operators ending with a subscript or superscript
479+
letter must be followed by a space when used in infix notation to distinguish them from variable names that begin
480+
with a subscript or superscript letter. For example, if `+ᵃ` is an operator, then `+ᵃx` must be written as `+ᵃ x`
481+
to distinguish it from `+ ᵃx`.
482+
483+
You can also find the numerical precedence for any binary or ternary operator via the
484+
built-in function `Base.operator_precedence`, where higher numbers take precedence:
431485

432486
```jldoctest
433487
julia> Base.operator_precedence(:+), Base.operator_precedence(:*), Base.operator_precedence(:.)
@@ -449,6 +503,8 @@ julia> Base.operator_associativity(:⊗), Base.operator_associativity(:sin), Bas
449503

450504
Note that symbols such as `:sin` return precedence `0`. This value represents invalid operators and not
451505
operators of lowest precedence. Similarly, such operators are assigned associativity `:none`.
506+
Some valid operators, such as `+`, `++`, `*`, and the comparison operators, also report associativity
507+
`:none` because they are neither left- nor right-associative.
452508

453509
[Numeric literal coefficients](@ref man-numeric-literal-coefficients), e.g. `2x`, are treated as multiplications with higher precedence than any other binary operation, with the exception of `^` where they have higher precedence only as the exponent.
454510

doc/src/manual/variables.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ digits (0-9 and other characters in categories Nd/No), as well as other Unicode
108108
and other modifying marks (categories Mn/Mc/Me/Sk), some punctuation connectors (category Pc),
109109
primes, and a few other characters.
110110

111-
Operators like `+` are also valid identifiers, but are parsed specially. In some contexts, operators
111+
[Operators](@ref Operator-Precedence-and-Associativity) like `+` are also valid identifiers, but
112+
are parsed specially. In some contexts, operators
112113
can be used just like variables; for example `(+)` refers to the addition function, and `(+) = f`
113114
will reassign it. Most of the Unicode infix operators (in category Sm), such as ``, are parsed
114115
as infix operators and are available for user-defined methods (e.g. you can use `const ⊗ = kron`
@@ -118,7 +119,6 @@ A space is required between an operator that ends with a subscript/superscript l
118119
variable name. For example, if `+ᵃ` is an operator, then `+ᵃx` must be written as `+ᵃ x` to distinguish
119120
it from `+ ᵃx` where `ᵃx` is the variable name.
120121

121-
122122
A particular class of variable names is one that contains only underscores. These identifiers are write-only. I.e. they can only be assigned values, which are immediately discarded, and their values cannot be used in any way.
123123

124124
```jldoctest

0 commit comments

Comments
 (0)