Beginner

Variables and Types in Icon

Learn about variables, data types, automatic type conversion, and null handling in Icon with practical Docker-ready examples

Icon takes a relaxed approach to variables and types. Variables don’t need declarations — just assign a value with := and the variable springs into existence. The type belongs to the value, not the variable, so any variable can hold any type at any time.

What makes Icon’s type system interesting is how it interacts with goal-directed evaluation. Unassigned variables have the special value &null, and Icon provides elegant operators to test for null that integrate with its success/failure model. Type conversions happen automatically in most contexts, keeping code concise while maintaining strong typing underneath.

In this tutorial, you’ll explore Icon’s built-in types, see how automatic conversion works, learn about the null value and its role in the language, and work with structured types like lists, sets, and tables.

Basic Variables and Types

Icon has a rich set of built-in types. Variables are untyped containers — the values they hold carry the type information. The type() function tells you what type a value is, and you can inspect it at any time.

Create a file named variables.icn:

procedure main()
    # Variables are created by assignment
    x := 42
    name := "Icon"
    pi := 3.14159
    vowels := 'aeiou'

    # The type() function returns a string naming the type
    write("x = ", x, " (", type(x), ")")
    write("name = ", name, " (", type(name), ")")
    write("pi = ", pi, " (", type(pi), ")")
    write("vowels = ", vowels, " (", type(vowels), ")")

    # Unassigned variables have the value &null
    write("y = (", type(y), ")")

    # The null test operators: / succeeds if null, \ succeeds if non-null
    if /y then write("y is null")
    if \x then write("x is not null")

    # Variables can change type freely
    x := "now I'm a string"
    write("x is now: ", x, " (", type(x), ")")

    # Arbitrary precision integers
    big := 2 ^ 64
    write("2^64 = ", big, " (", type(big), ")")

    # Negative numbers and zero
    neg := -17
    zero := 0
    write("neg = ", neg, ", zero = ", zero)
end

This example covers Icon’s core scalar types: integers (with arbitrary precision), real numbers, strings, and csets (character sets). The cset type — written with single quotes — is unique to Icon and represents an unordered set of characters, which is useful for string scanning operations.

Automatic Type Conversion

One of Icon’s practical strengths is automatic type conversion. When an operation expects a certain type, Icon converts the value if possible. If the conversion can’t be done, the expression fails rather than raising an error — consistent with Icon’s goal-directed philosophy.

Create a file named variables_conversion.icn:

procedure main()
    write("--- Automatic Conversion ---")

    # String to number in arithmetic
    result := "25" + 17
    write("\"25\" + 17 = ", result, " (", type(result), ")")

    # Number to string in concatenation
    greeting := "Version " || 9
    write(greeting, " (", type(greeting), ")")

    # Integer to real in mixed arithmetic
    mixed := 7 / 2.0
    write("7 / 2.0 = ", mixed, " (", type(mixed), ")")

    # Integer division (both operands are integers)
    intdiv := 7 / 2
    write("7 / 2 = ", intdiv, " (", type(intdiv), ")")

    write()
    write("--- Explicit Conversion ---")

    # Explicit conversion functions
    i := integer("99")
    write("integer(\"99\") = ", i, " (", type(i), ")")

    r := real(42)
    write("real(42) = ", r, " (", type(r), ")")

    s := string(3.14)
    write("string(3.14) = ", s, " (", type(s), ")")

    # numeric() converts to integer or real as appropriate
    n1 := numeric("100")
    n2 := numeric("3.5")
    write("numeric(\"100\") is ", type(n1))
    write("numeric(\"3.5\") is ", type(n2))

    write()
    write("--- Failed Conversion ---")

    # Conversion failure integrates with goal-directed evaluation
    if integer("hello") then
        write("converted")
    else
        write("integer(\"hello\") failed - not a number")

    # Using the default operator to handle conversion failure
    val := integer("abc") | 0
    write("integer(\"abc\") defaulted to: ", val)
end

Notice how failed conversions don’t crash the program. The expression integer("hello") simply fails, and Icon’s control structures handle failure naturally. The | operator provides an alternative value when the left side fails — a pattern you’ll use often in Icon.

Structured Types

Icon provides several built-in structured types: lists, sets, and tables. These are mutable, dynamically sized, and can hold values of any type.

Create a file named variables_structures.icn:

record Point(x, y)

procedure main()
    write("--- Lists ---")
    colors := ["red", "green", "blue"]
    write("colors has ", *colors, " elements")
    every write("  ", !colors)

    # Lists can hold mixed types
    mixed := [1, "two", 3.0, ["nested"]]
    write("mixed types: ", type(mixed[1]), ", ", type(mixed[2]),
          ", ", type(mixed[3]), ", ", type(mixed[4]))

    write()
    write("--- Sets ---")
    fruits := set(["apple", "banana", "cherry", "apple"])
    write("fruits has ", *fruits, " unique elements")
    insert(fruits, "date")
    if member(fruits, "banana") then
        write("  banana is in the set")

    write()
    write("--- Tables ---")
    ages := table(0)
    ages["Alice"] := 30
    ages["Bob"] := 25
    ages["Carol"] := 35
    write("Alice is ", ages["Alice"])
    write("Unknown defaults to ", ages["nobody"])

    write()
    write("--- Records ---")
    p := Point(10, 20)
    write("Point: (", p.x, ", ", p.y, ")")
    p.x := 50
    write("Modified: (", p.x, ", ", p.y, ")")

    write()
    write("--- Size Operator * ---")
    write("string length: ", *"hello")
    write("list size: ", *colors)
    write("set size: ", *fruits)
    write("table size: ", *ages)
end

The * operator returns the size of any collection or the length of a string. The ! operator generates all elements of a collection. These two operators work uniformly across all structured types, which is one of Icon’s elegant design choices.

Running with Docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Pull the Docker image
docker pull codearchaeology/icon:latest

# Run the basic variables example
docker run --rm -v $(pwd):/app -w /app codearchaeology/icon:latest sh -c "icont variables.icn && ./variables"

# Run the conversion example
docker run --rm -v $(pwd):/app -w /app codearchaeology/icon:latest sh -c "icont variables_conversion.icn && ./variables_conversion"

# Run the structures example
docker run --rm -v $(pwd):/app -w /app codearchaeology/icon:latest sh -c "icont variables_structures.icn && ./variables_structures"

Expected Output

Running variables.icn:

x = 42 (integer)
name = Icon (string)
pi = 3.14159 (real)
vowels = aeiou (cset)
y = (null)
y is null
x is not null
x is now: now I'm a string (string)
2^64 = 18446744073709551616 (integer)
neg = -17, zero = 0

Running variables_conversion.icn:

--- Automatic Conversion ---
"25" + 17 = 42 (integer)
Version 9 (string)
7 / 2.0 = 3.5 (real)
7 / 2 = 3 (integer)

--- Explicit Conversion ---
integer("99") = 99 (integer)
real(42) = 42.0 (real)
string(3.14) = 3.14 (string)
numeric("100") is integer
numeric("3.5") is real

--- Failed Conversion ---
integer("hello") failed - not a number
integer("abc") defaulted to: 0

Running variables_structures.icn:

--- Lists ---
colors has 3 elements
  red
  green
  blue
mixed types: integer, string, real, list

--- Sets ---
fruits has 3 unique elements
  banana is in the set

--- Tables ---
Alice is 30
Unknown defaults to 0

--- Records ---
Point: (10, 20)
Modified: (50, 20)

--- Size Operator * ---
string length: 5
list size: 3
set size: 4
table size: 3

Key Concepts

  • No declarations needed — variables are created by assignment with := and can hold any type
  • Types belong to values — use type() to inspect the type of any value at runtime
  • &null and null testing — unassigned variables are &null; use /x to test for null and \x to test for non-null
  • Automatic type conversion — Icon converts between strings, integers, and reals as needed, failing gracefully when conversion is impossible
  • Character sets (csets) — single-quoted literals like 'aeiou' represent sets of characters, useful for string scanning
  • Structured types — lists, sets, tables, and records provide flexible data organization with uniform operators like * (size) and ! (generate elements)
  • Failed conversion = expression failure — invalid conversions don’t crash; they integrate with Icon’s goal-directed evaluation model
  • Arbitrary precision integers — Icon integers have no size limit, supporting exact arithmetic on large numbers

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