Operators in Icon
Explore arithmetic, comparison, logical, and Icon-specific operators including string concatenation, alternation, and goal-directed evaluation
Operators in Icon look familiar at first glance — +, -, *, / work just as you’d expect. But Icon’s operators have a twist: every operator is an expression that can either succeed (producing a value) or fail (producing no value). This goal-directed model gives Icon operators capabilities that go well beyond what most languages offer.
Icon also introduces operators you won’t find in mainstream languages: || for string concatenation, | for alternation, ! for element generation, and :=: for exchange. Comparison operators don’t return booleans — they return their right operand on success and fail otherwise, which lets you chain them naturally.
In this tutorial, you’ll explore Icon’s full operator palette and see how its evaluation model turns ordinary-looking expressions into powerful tools.
Arithmetic and Assignment Operators
Icon supports the standard arithmetic operators along with augmented assignment forms. Integers are arbitrary precision, so overflow is not a concern for typical computations.
Create a file named operators.icn:
procedure main()
# Arithmetic operators
a := 17
b := 5
write("a = ", a, ", b = ", b)
write("a + b = ", a + b)
write("a - b = ", a - b)
write("a * b = ", a * b)
write("a / b = ", a / b) # integer division when both are integers
write("a % b = ", a % b) # remainder
write("a ^ b = ", a ^ b) # exponentiation
write("-a = ", -a)
# Real number division
x := 17.0
write("17.0 / 5 = ", x / b) # mixed: result is real
# Augmented assignment operators
n := 10
n +:= 5; write("n after +:= 5 -> ", n)
n -:= 3; write("n after -:= 3 -> ", n)
n *:= 2; write("n after *:= 2 -> ", n)
n /:= 4; write("n after /:= 4 -> ", n)
n ^:= 3; write("n after ^:= 3 -> ", n)
# Exchange operator :=: swaps two variables
p := 1
q := 99
p :=: q
write("after p :=: q -> p = ", p, ", q = ", q)
end
:= is the assignment operator (Icon does not use = for assignment — = is numeric equality). Every augmented operator follows the pattern op:= rather than := op, so it reads as “operate-and-assign.”
String Operators
Icon predates regular expressions in mainstream languages and offers its own elegant operators for string work.
Create a file named string_ops.icn:
procedure main()
greeting := "Hello"
target := "Icon"
# Concatenation with ||
msg := greeting || ", " || target || "!"
write(msg)
# Repetition: produces n copies of a string
bar := "-" || repl("=", 10) || "-"
write(bar)
# Size of a string with *
write("length of msg = ", *msg)
# Subscripting: s[i] picks one character, s[i:j] picks a substring
write("first char = ", msg[1])
write("last char = ", msg[-1])
write("chars 1..5 = ", msg[1:6]) # 1:6 means positions 1 up to 6
write("chars 8..end = ", msg[8:0]) # 0 means "end of string"
# Lexical comparison: ==, ~==, <<, <<=, >>, >>=
if "apple" << "banana" then
write("'apple' << 'banana' succeeds")
if "icon" == ("ic" || "on") then
write("string equality holds")
end
The repetition word repl(s, n) builds a repeated string. Note that * applied to a string returns its length — * is overloaded based on operand type. Lexical (string) comparison uses doubled angle brackets (<<, >>) to distinguish from numeric comparison.
Comparison and Logical Operators
Comparison operators in Icon look standard but behave uniquely: on success they return their right operand, and on failure they produce no value. This lets you chain comparisons in ways that read naturally.
Create a file named compare_logic.icn:
procedure main()
x := 25
# Numeric comparison operators: =, ~=, <, <=, >, >=
if x = 25 then write("x equals 25")
if x ~= 0 then write("x is not zero")
# Chained comparison: 0 < x < 100 succeeds when both hold.
# (0 < x) returns x; then (x < 100) tests that against 100.
if 0 < x < 100 then
write("x is between 0 and 100 (chained comparison)")
# Alternation |: try the left side, then the right
color := "red" | "green" | "blue"
write("first value of alternation: ", color)
# every iterates over all values an expression can produce
every c := ("red" | "green" | "blue") do
write(" alternation value: ", c)
# Conjunction & : evaluate left, then right; result is the rightmost
if (x > 0) & (x < 100) then
write("both conditions true (conjunction)")
# Negation: 'not' inverts success/failure
if not (x = 0) then
write("x is not zero (via not)")
# Default operator \ and null-check /
y := &null
z := \y | "fallback" # if y is non-null, use it; else use fallback
write("z = ", z)
end
& (conjunction) and | (alternation) take the place of the more familiar boolean and/or. There are no boolean values in Icon — success and failure carry that meaning.
Generators, Goal-Directed Evaluation, and Precedence
Icon’s most distinctive operators produce multiple values. When combined with every, these unlock concise pattern-driven code.
Create a file named generators.icn:
procedure main()
# The "to" operator generates a sequence
every i := 1 to 5 do
writes(i, " ")
write()
# "to ... by" controls the step
every i := 10 to 1 by -2 do
writes(i, " ")
write()
# The element generator ! produces successive elements of a list/string
L := [10, 20, 30, 40]
every writes(!L, " ")
write()
# ! on a string generates each character
every writes(!"abc", " ")
write()
# Goal-directed evaluation: find every i*j that equals 12
every i := 1 to 6 & j := 1 to 6 do
if i * j = 12 then
write(" ", i, " * ", j, " = 12")
# Operator precedence demo (highest to lowest in this expression):
# ^ (right-associative) has higher precedence than * /
# * / % are higher than + -
# parentheses force evaluation order
write("2 + 3 * 4 = ", 2 + 3 * 4) # 14
write("(2 + 3) * 4 = ", (2 + 3) * 4) # 20
write("2 ^ 3 ^ 2 = ", 2 ^ 3 ^ 2) # 512 (right-assoc: 2 ^ (3 ^ 2))
end
The to and ! operators are generators — they don’t return a single value, they produce a stream of values driven by the surrounding context. In an if they yield the first; in every they yield each in turn.
Running with Docker
| |
Expected Output
Running operators:
a = 17, b = 5
a + b = 22
a - b = 12
a * b = 85
a / b = 3
a % b = 2
a ^ b = 1419857
-a = -17
17.0 / 5 = 3.4
n after +:= 5 -> 15
n after -:= 3 -> 12
n after *:= 2 -> 24
n after /:= 4 -> 6
n after ^:= 3 -> 216
after p :=: q -> p = 99, q = 1
Running string_ops:
Hello, Icon!
-==========-
length of msg = 12
first char = H
last char = !
chars 1..5 = Hello
chars 8..end = Icon!
'apple' << 'banana' succeeds
string equality holds
Running compare_logic:
x equals 25
x is not zero
x is between 0 and 100 (chained comparison)
first value of alternation: red
alternation value: red
alternation value: green
alternation value: blue
both conditions true (conjunction)
x is not zero (via not)
z = fallback
Running generators:
1 2 3 4 5
10 8 6 4 2
10 20 30 40
a b c
2 * 6 = 12
3 * 4 = 12
4 * 3 = 12
6 * 2 = 12
2 + 3 * 4 = 14
(2 + 3) * 4 = 20
2 ^ 3 ^ 2 = 512
Key Concepts
- Assignment is
:=, not=—=is numeric equality. The augmented forms followop:=(e.g.+:=). - Comparison operators return their right operand on success, fail otherwise. This enables natural chaining like
0 < x < 100. - String operators are first-class:
||for concatenation,*sfor length,s[i:j]for slicing, and<</>>for lexical ordering. - Logical glue is
&and|, notand/or. There are no booleans — success and failure replace them. |is alternation, a generator — it produces each operand in turn when in a generator-consuming context likeevery.!generates elements of a list or characters of a string;toandto ... bygenerate numeric sequences.:=:exchanges two values without a temporary — a tiny but characteristic Icon convenience.- Precedence is conventional:
^(right-associative) binds tighter than* / %, which bind tighter than+ -. Parentheses always work.
Running Today
All examples can be run using Docker:
docker pull codearchaeology/icon:latest
Comments
Loading comments...
Leave a Comment