Beginner

Operators in Julia

Learn arithmetic, comparison, logical, updating, and broadcasting operators in Julia with practical Docker-ready examples

Operators are the verbs of a programming language—they take values and produce new ones. Julia’s operator design reflects its roots in scientific computing: most operators look exactly like the mathematical notation you’d write on paper, including Unicode symbols like ÷ for integer division and dot-prefixed operators that broadcast across whole arrays.

What makes operators interesting in Julia is that they’re really just functions with special infix syntax. a + b is shorthand for +(a, b), and because of multiple dispatch, the meaning of + depends on the types of its arguments. This is why you can define + for your own types and have it Just Work with the rest of the language.

In this tutorial you’ll see Julia’s arithmetic, comparison, logical, updating, and string operators, plus a feature unique to Julia and its array-language ancestors: broadcasting with the dot syntax.

Arithmetic Operators

Julia supports the usual arithmetic operators plus a few extras for integer division and exact rationals.

Create a file named arithmetic.jl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
a = 17
b = 5

println("a + b = ", a + b)
println("a - b = ", a - b)
println("a * b = ", a * b)
println("a / b = ", a / b)     # always returns Float64
println("a ÷ b = ", a ÷ b)     # integer division (also: div(a, b))
println("a % b = ", a % b)     # remainder (also: rem(a, b))
println("a ^ b = ", a ^ b)     # exponentiation (not bitwise XOR)

# Unary minus
println(-a)

# Numeric literal coefficients: 2x means 2 * x
x = 10
println(2x + 3)

A few things to notice: / always produces a floating-point result even with two integers, ÷ (typed \div<Tab> in the REPL) is integer division, and ^ is exponentiation—not XOR like in C. Julia also lets you write 2x instead of 2*x when the left side is a numeric literal, which makes math-heavy code read naturally.

Comparison Operators and Chained Comparisons

Comparison operators return Bool values, and Julia uniquely supports chained comparisons that mirror mathematical notation.

Create a file named comparison.jl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
println(3 == 3)
println(3 != 4)
println(3 < 4)
println(3 >= 3)

# Chained comparisons read like math
x = 5
println(1 < x < 10)        # true
println(0 < x < 3)         # false

# === checks identity (same object), == checks value
println(1 == 1.0)          # true (numerically equal)
println(1 === 1.0)         # false (different types)

# isapprox / ≈ for floating-point fuzzy equality
println(0.1 + 0.2 == 0.3)
println(0.1 + 0.2  0.3)

Chained comparisons like 1 < x < 10 are not parsed as (1 < x) < 10 (which would be a type error in many languages); Julia evaluates each comparison and ANDs the results. The operator (typed \approx<Tab>) compares floating-point numbers with a tolerance—essential when working with arithmetic that isn’t exact.

Logical and Bitwise Operators

Logical operators short-circuit, and bitwise operators work on integer bits.

Create a file named logical.jl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Logical (short-circuiting)
println(true && false)
println(true || false)
println(!true)

# Short-circuit is also used for guarded actions
x = 7
x > 0 && println("positive")
x < 0 || println("not negative")

# Bitwise operators on integers
println(0b1100 & 0b1010)   # AND -> 0b1000 = 8
println(0b1100 | 0b1010)   # OR  -> 0b1110 = 14
println(0b1100  0b1010)   # XOR -> 0b0110 = 6  (also: xor())
println(~0b1100 & 0xff)    # NOT lower byte -> 243
println(1 << 4)            # left shift -> 16

The symbol (typed \xor<Tab>) is the bitwise XOR operator. Julia reserved ^ for exponentiation because that’s what mathematicians expect.

Updating (Compound Assignment) Operators

Every binary arithmetic operator has an updating form that rebinds the variable.

Create a file named updating.jl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
x = 10
x += 5     # x = x + 5
x -= 2     # x = x - 2
x *= 3     # x = x * 3
x ÷= 2     # x = x ÷ 2
x ^= 2     # x = x ^ 2
println("x = $x")

# Works on strings too via *
s = "Hello"
s *= ", World!"
println(s)

Note that x += 5 in Julia rebinds x rather than mutating it—immutable values stay immutable, which matters for performance reasoning.

Broadcasting: The Dot Operators

This is where Julia’s array-language heritage shines. Prefix any operator (or function) with a . to apply it element-wise to arrays of compatible shape—no explicit loop needed.

Create a file named broadcasting.jl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
v = [1, 2, 3, 4]
w = [10, 20, 30, 40]

# Element-wise arithmetic
println(v .+ w)      # [11, 22, 33, 44]
println(v .* w)      # [10, 40, 90, 160]
println(v .^ 2)      # [1, 4, 9, 16]

# Scalar broadcasts against the array
println(v .+ 100)    # [101, 102, 103, 104]

# Element-wise comparison, reduced with any/all
println(any(v .> 3)) # true
println(all(v .> 0)) # true

# Functions broadcast too with the dot
println(sqrt.(v))    # [1.0, 1.414..., 1.732..., 2.0]

# Fused broadcasting: this is one pass, no temporaries
result = 2 .* v .+ 1
println(result)

A key performance property: chained dot operations fuse into a single loop with no intermediate arrays. 2 .* v .+ 1 allocates exactly one result array, not two. This is why Julia code can look high-level and still match hand-written C loops.

String Operators and Operator Precedence

Julia uses * (not +) for string concatenation, which surprises newcomers but reflects the mathematical view of strings as elements of a non-commutative monoid.

Create a file named strings_and_precedence.jl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# String concatenation with *
greeting = "Hello" * ", " * "World!"
println(greeting)

# Repetition with ^
println("ab"^3)             # ababab

# Precedence: * binds tighter than +
println(2 + 3 * 4)          # 14
println((2 + 3) * 4)        # 20

# ^ is right-associative
println(2^3^2)              # 2^(3^2) = 2^9 = 512

# Comparison binds tighter than &&
println(1 < 2 && 3 < 4)     # true

When in doubt, reach for parentheses—Julia has roughly 30 precedence levels, and even experienced users rarely memorize them all.

Running with Docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Pull the Julia image
docker pull julia:1.11-alpine

# Run each example
docker run --rm -v $(pwd):/app -w /app julia:1.11-alpine julia arithmetic.jl
docker run --rm -v $(pwd):/app -w /app julia:1.11-alpine julia comparison.jl
docker run --rm -v $(pwd):/app -w /app julia:1.11-alpine julia logical.jl
docker run --rm -v $(pwd):/app -w /app julia:1.11-alpine julia updating.jl
docker run --rm -v $(pwd):/app -w /app julia:1.11-alpine julia broadcasting.jl
docker run --rm -v $(pwd):/app -w /app julia:1.11-alpine julia strings_and_precedence.jl

Expected Output

Running arithmetic.jl:

a + b = 22
a - b = 12
a * b = 85
a / b = 3.4
a ÷ b = 3
a % b = 2
a ^ b = 1419857
-17
23

Running comparison.jl:

true
true
true
true
true
false
true
false
false
true

Running logical.jl:

false
true
false
positive
not negative
8
14
6
243
16

Running updating.jl:

x = 361
Hello, World!

Running broadcasting.jl:

[11, 22, 33, 44]
[10, 40, 90, 160]
[1, 4, 9, 16]
[101, 102, 103, 104]
true
true
[1.0, 1.4142135623730951, 1.7320508075688772, 2.0]
[3, 5, 7, 9]

Running strings_and_precedence.jl:

Hello, World!
ababab
14
20
512
true

Key Concepts

  • Operators are functions: a + b is syntactic sugar for +(a, b), dispatched on argument types—you can extend +, *, == for your own types.
  • / vs ÷: / always produces a Float64; ÷ (or div) does integer division. ^ is exponentiation, not XOR—use or xor() for XOR.
  • Chained comparisons: 1 < x < 10 works as expected, parsed as 1 < x && x < 10.
  • Identity vs equality: == compares values, === compares identity (and type), compares floats with tolerance.
  • Broadcasting with .: prefix any operator or function with . to apply it element-wise. Chained dot operations fuse into a single loop with no temporary arrays.
  • Strings use * and ^: concatenation is * (think monoid), repetition is ^. Use $x interpolation for mixing values into strings.
  • Numeric literal coefficients: 2x means 2 * x, but only when the left side is a numeric literal—useful for math-heavy code.
  • Short-circuit as control flow: cond && action() and cond || fallback() are idiomatic Julia for guarded one-liners.

Running Today

All examples can be run using Docker:

docker pull julia:1.11-alpine
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining