CS 420 · Spring 2026

A language that
changes its own code.

You write the rules a function has to follow. Flexigen picks an implementation that fits, and picks a different one when the input changes.

sort.flex
// Declare what must hold. The compiler decides how.
adaptive fn sort(xs: List<Int>) -> List<Int> {
  spec {
    ensure sorted(xs)   // invariant the runtime cannot break
    optimize speed       // what to optimize for
    keep stable          // extra constraint
  }
  baseline { merge_sort(xs) }
  variant timsort    when mostly_sorted(xs)
  variant insertion  when len(xs) < 32
}

Write what,
not how.

A function written today gets shipped against the data, hardware, and workload that exist today. When any of those change, the function is wrong without warning. Flexigen lets the function carry its own decisions about how to run.

01
Spec is the contract
The spec block names what the function has to guarantee, what to optimize for, and any extra constraints. The compiler enforces it. A variant that violates it gets rejected before it can run.
02
Variants run only after they pass
A variant cannot ship until it passes the same test suite as the baseline. Public types and security rules cannot be changed by an adaptation unless the spec explicitly says they can.
03
AI proposals get gated
An external tool, including an AI assistant, can suggest a variant. The compiler treats it like any other variant. It runs the type checks, the contracts, and the benchmark. Nothing auto-deploys.
04
Every adaptation is replayable
The runtime writes a log of which variant ran and why. You can pin a function to one version, replay an old run with the same decisions it made then, or roll back to a known-good version.

Adaptive functions.

Every adaptive function has four parts. The first two define what is allowed to happen. The third lists alternative implementations. The fourth records what actually ran.

01
spec: the contract
The spec block lists what the function must guarantee, the property to optimize, and any extra constraints. A variant that violates any clause is rejected at compile time.
02
baseline: the reference implementation
An implementation that is always allowed to run. Variants are compared against it on correctness and performance. If no variant qualifies, the baseline runs.
03
variant: an alternate with a guard
Each variant has a when guard. At call time the runtime evaluates the guards, picks the first variant whose guard matches, and falls back to baseline if none do.
04
report: a record of what actually ran
The adaptation report logs the variant that ran for each call and the reason the runtime picked it. Replaying the report reproduces the same execution.
dup.flex
// Picks a scan strategy by input shape
adaptive fn has_duplicates(a: List<Int>) -> Bool {
  spec { ensure exact; optimize speed }

  // O(n^2). The reference.
  baseline { nested_scan(a) }

  // O(n) hash. Default fast path.
  variant hashset_scan

  // O(n) bitmap when values fit in memory.
  variant bitmap_scan when max(a) < 1_000_000
}
Adaptation Report
[AdaptReport] has_duplicates:
  selected 'hashset_scan'
  condition met: max(a) < 1_000_000

Five programs.
One interpreter.

Hello world, FizzBuzz, list operations, an adaptive Fibonacci, and a duplicate-detection report. All run by the same interpreter, all in the same .flex syntax.

hello_world.flex
Hello world and clamp
The starter program. Variable declarations, function definitions, string concatenation, list iteration, and a clamp function that caps each score at a limit.
hello_world.flex
let name: String = "World"
let limit: Int = 90
let scores = List<Int>[88, 92, 75, 61, 99]

fn greet(who: String) -> String {
  return "Hello, " + who + "!"
}

fn clamp(x: Int) -> Int {
  if x > limit { return limit }
  else { return x }
}

print(greet(name))
for n in scores { print(clamp(n)) }
Interpreter Output
── Running hello_world.flex ──
Hello, World! Welcome to Flexigen v1
5 squared is: 25
10 squared is: 100
Clamped scores:
88
90
75
61
90
fibonacci.flex
Adaptive Fibonacci
The baseline is fib_recursive. The variant fib_iterative activates when n > 10. For each call the runtime picks one and writes the choice to the adaptation report.
fibonacci.flex
adaptive fn fibonacci(n: Int) -> Int {
  spec { ensure exact; optimize speed }
  baseline { fib_recursive(n) }
  variant fib_iterative when n > 10
  variant fib_memoized  when n > 30
}
Interpreter Output
── Running fibonacci.flex ──
fib(0) = 0
fib(1) = 1
fib(2) = 1
fib(3) = 2
fib(4) = 3
fib(5) = 5
fib(6) = 8
fib(7) = 13
fib(8) = 21
fib(9) = 34
fib(10) = 55
fib(11) = 89

[AdaptReport] fibonacci:
  selected 'fib_iterative'
  condition met: n > 10
list_ops.flex
List operations
Sum and max over a list, filtering even numbers, doubling values, and an adaptive sort. The sort uses merge sort as baseline. Lists shorter than 32 take an insertion-sort variant instead.
list_ops.flex
let numbers = List<Int>[3,7,2,9,4,6,1,8,5,10]

fn is_even(n: Int) -> Bool { return n % 2 == 0 }
fn double(n: Int) -> Int  { return n * 2 }

adaptive fn sort(xs: List<Int>) -> List<Int> {
  spec { ensure sorted(xs); keep stable }
  baseline { merge_sort(xs) }
  variant insertion when len(xs) < 32
}
Interpreter Output
── Running list_ops.flex ──
Original list: [3, 7, 2, 9, 4, 6, 1, 8, 5, 10]
Sum: 55
Max: 10
Even numbers doubled:
4
8
12
16
20
Sorted: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[AdaptReport] sort:
  selected 'baseline'
  default baseline selected
fizzbuzz.flex
FizzBuzz
FizzBuzz in Flexigen syntax. A while loop from 1 to 30, modulo arithmetic in the conditionals, and a string-returning function.
fizzbuzz.flex
fn fizzbuzz(n: Int) -> String {
  if n % 15 == 0 { return "FizzBuzz" }
  if n % 3  == 0 { return "Fizz" }
  if n % 5  == 0 { return "Buzz" }
  return n
}

let i: Int = 1
while i <= 30 {
  print(fizzbuzz(i))
  i = i + 1
}
Interpreter Output
── Running fizzbuzz.flex ──
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
data_analysis.flex
Adaptive data analysis
The complex program. It runs an adaptive duplicate-detection function on two datasets, prints summary statistics for each, and dumps the adaptation report at the end so you can see which variant ran.
data_analysis.flex
adaptive fn has_duplicates(a: List<Int>) -> Bool {
  spec { ensure exact; optimize speed }
  baseline { nested_scan(a) }
  variant hashset_scan
  variant bitmap_scan when max(a) < 1_000_000
}

let dataset_a = List<Int>[10,25,37,42,58...]
let dataset_b = List<Int>[5,12,33,12,47...]

print(has_duplicates(dataset_a))
print(has_duplicates(dataset_b))
Interpreter Output
=== Flexigen Data Analysis Report ===

--- Dataset A ---
Values: [10, 25, 37, 42, 58, 61, 79, 83, 91, 100]
Length: 10  Mean: 58  Min: 10  Max: 100
Has duplicates: false
Count above 50: 6

--- Dataset B ---
Values: [5, 12, 33, 12, 47, 5, 88, 91, 33, 100]
Length: 10  Mean: 42  Min: 5  Max: 100
Has duplicates: true
Count above 50: 3

=== End of Report ===

[AdaptReport] has_duplicates:
  selected 'hashset_scan', condition met

Tools
around the language.

The interpreter is the core. The rest is what a real version of Flexigen would need to be useful: a way to compile, a way to measure, a way to inspect, and a way to audit. The current prototype implements flexc. The others are described here as proposed work.

flexc
Flexigen interpreter
The prototype that runs the .flex programs in this submission. Lexes, parses, type-checks variants, evaluates the spec, and selects an implementation at each call.
bench
FlexBench (proposed)
A profiler that measures baseline vs variant performance and feeds that data back into the runtime so the choice is driven by real measurements.
scope
FlexScope (proposed)
A timeline view of an execution. Which variant ran on each call, what guard matched, what the profile said.
audit
FlexAudit (proposed)
An append-only log of every adaptation. Replay a past run with the same variant choices, pin a function to a specific version, or roll back.
pkg
flexpkg (proposed)
A package manager. Versions Flexigen libraries and resolves dependencies between them.
vsc
VS Code extension (proposed)
Syntax highlighting, an inline view of the most recent adaptation report, and a way to pick a variant by hand.
Standard Libraries
flex.algorithms flex.graph flex.data flex.math flex.robotics flex.ai_proposals flex.testing

Built by three.

CS 420, Programming Language Design, SDSU, Spring 2026.

NM
Nikhil Maharaj
RC
Ryan Collins
CS
Chris Sapien