TIP 730: Switching by Integers

Login
Bounty program for improvements to Tcl and certain Tcl packages.
 Author:         Donal K. Fellows <dkf@users.sf.net>
 State:          Final
 Type:           Project
 Tcl-Version:    9.1
 Vote:           Done
 Created:        08-Sep-2025
 Keywords:       Tcl, switch, jump table
 Tcl-Branch:     tip730-switch-integer
 Votes-For:      HO, DKF, APN, SL, AK, MC
 Votes-Against:  none
 Votes-Present:  none

Abstract

Tcl has switch but is quite inefficient at handling numbers with it. This TIP adds the option to choose the arm by an integer value rather than by string form.

Rationale

The switch command has three different ways of matching its value parameter:

  1. By exact string comparison.
  2. By glob matching.
  3. By regular expression matching.

None of these are particularly good for naturally numeric values. While that can't really be helped for floating point numbers (as the reams written on floating point attest to), we can certainly do better for integers. In particular, for integers that fit into a Tcl_WideInt, we can use an efficient approach. This will also make switch more useful for comparing a value against various bit patterns, as we won't force complex shenanigans just to make things readable.

Specification

The switch command shall gain an extra option, -integer. This option shall be illegal to use in combination with -exact, -glob, or -regexp. If specified, each of the values to match against (except a possible final default) must be an integer that can be parsed with Tcl_GetWideIntFromObj(), and the arm that is selected will be the first one that is integer-equal to the value parameter.

While not handling bigger integers is technically unfortunate, this could be added in the future (by relaxing the constraint described above) and is, in practice, an uncommon requirement because the likelihood of a value being used as a switch arm is likely approximately inversely proportional to the number of bits required to express it.

Consequences

This will mean that we can do this:

set x 0o37
switch -integer -- $x {
    37 {
        puts "false matched"
    }
    0x1f {
        puts "matched"
    }
    default {
        puts "not matched"
    }
}

and expect to have matched printed.

Compatibility

There are two key cases for compatibility notes:

  1. When someone uses switch (with more than two arguments) passing -integer as a thing to compare and yet not passing --. However, if they're doing that then they've almost certainly got some nasty bugs anyway; switch has always behaved oddly in some edge cases and this TIP doesn't consider changing that to be in scope. Unless you're using the two-argument version of switch (which is always an exact string comparison mode) you should pass -- to mark the end of the options.

  2. When someone uses -i or -in as a (no-longer unique) prefix of -indexvar, but we don't (and have never) actually recommend using option abbreviations precisely because that's a risk for our flexibility going forward. Note that the -indexvar option also requires -regexp, which it is illegal to use at the same time as -integer. (That's the same as for any other mode option for switch. Theoretically, the option parser could be taught to handle this case; the implementation does not in order to keep parsing simple.)

Implementation

See the tip730-switch-integer branch.

Uses the jumpTableNum bytecode instruction introduced by #720 for the bytecode compiled version.

Copyright

This document has been placed in the public domain.

History