Beginner

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Pull the official image
docker pull codearchaeology/icon:latest

# Compile and run the main operators example
docker run --rm -v $(pwd):/app -w /app codearchaeology/icon:latest \
    sh -c "icont operators.icn && ./operators"

# Compile and run the string operators example
docker run --rm -v $(pwd):/app -w /app codearchaeology/icon:latest \
    sh -c "icont string_ops.icn && ./string_ops"

# Compile and run the comparison/logical example
docker run --rm -v $(pwd):/app -w /app codearchaeology/icon:latest \
    sh -c "icont compare_logic.icn && ./compare_logic"

# Compile and run the generators example
docker run --rm -v $(pwd):/app -w /app codearchaeology/icon:latest \
    sh -c "icont generators.icn && ./generators"

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 follow op:= (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, *s for length, s[i:j] for slicing, and << / >> for lexical ordering.
  • Logical glue is & and |, not and/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 like every.
  • ! generates elements of a list or characters of a string; to and to ... by generate 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
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining