Dynamic arrays gave you growth; this page gives you order — and its opposite, on purpose. The arrays unit sorts and copies pieces; the random unit shuffles and rolls, and its disorder is the reproducible kind: seeded, defined by pure integer arithmetic, the same on every machine at every tier.

The example is examples/OrderAndDisorder in the tutorial repository.

Getting the file

make -C mica-container/examples/OrderAndDisorder run
OrderAndDisorder

sorted      1 3 4 7 8 9
middle three 4 7 8
shuffled(7) 3 9 1 4 8 7  - sum still 32
three dice  4 5 1

Run it on another machine, another architecture, another optimization tier: the shuffled line and the dice are the same. That is the page’s headline, and it is not an accident.

The example, walked

Sort: the guarantees a systems library owes

Sort(address ns);

Sort is a native generic heapsort over any dynamic array whose elements are ordered. The comparison is the element type’s own < — the generics machinery clones the routine per element type and compares in line, so there is no comparator to hand over and nothing the type checker cannot see. The properties are the ones worth promising: it sorts in place with no allocation at all, so it works unchanged where no heap exists; its worst case equals its best at O(n log n), so no adversarial input degrades it; and its stack use is a handful of locals however large the array grows.

Sort does not keep equal elements in the order they had. Over numbers and strings that is seldom visible, because equal values look alike; it matters the moment records sort by one of their fields, which is what the next section shows.

Sorting records by a key, and keeping equal keys in order

A record has no order of its own, so a sort by one of its fields takes that field’s values as a key array: one key per element, at the same position, filled by your own loop. SortByKeys orders the keys and carries every element along with its key, in place and with no allocation, by the same heapsort as Sort. StableSortByKeys does the same and keeps the elements of equal keys in the order they had, so a roster already in name order stays in name order inside each age:

{ Roster sorts people by age and keeps the people of one age in name order. }
program Roster;

imp
    WriteLn, Append, Length : std;
    StableSortByKeys, List, SortList : arrays;

type
    { a person is a name and an age }
    Person = record
        name : string;
        age : int64;
    end;

var
    people : List of Person;
    ages : SortList of int64;
    i : int64;

{ The roster grows by one person. }
procedure Add(name : string, age : int64);
var
    person : Person;
begin
    person.name := name;
    person.age := age;
    Append(address people, person);
end;

begin
    Add("Ada", 36);
    Add("Barbara", 60);
    Add("Charles", 36);
    Add("Edsger", 60);
    Add("Grace", 85);

    { the key array holds each person's age at that person's position }
    for i := 0 to Length(people) - 1 do begin
        Append(address ages, people[i].age);
    end;
    StableSortByKeys(address people, address ages);

    for i := 0 to Length(people) - 1 do begin
        WriteLn("%lld %ls", people[i].age, people[i].name);
    end;
end.

Run it with mica Roster.mica:

36 Ada
36 Charles
60 Barbara
60 Edsger
85 Grace

After the sort the keys ascend and each one still stands beside its own person, so a second sort by another field takes a new key array filled from the sorted records. StableSort is the stable twin of Sort for an array of ordered elements. The stable sorts are merge sorts, and their price is memory: one buffer of half the array’s elements (and of half its keys), taken when the sort starts and given back when it returns, and none for an array of sixteen elements or fewer. Their worst case is O(n log n) like Sort’s, and an array already in order costs one comparison per merge. Where memory has to stay flat, Sort and SortByKeys are the in-place road.

SubArray: the named piece

SubArray(address ns, 2, 3, address piece);

Elements 2, 3 and 4, copied into a list the caller owns — the value rule’s spelling of a slice, consistent with everything the slicing page taught: a piece you name is a copy you own.

Shuffle: disorder you can rerun

rng := Seeded(7);
Shuffle(address ns, address rng);

The generator behind Shuffle is seeded and deterministic: its whole definition is integer arithmetic, so the same seed yields the same sequence on every architecture at every tier — the determinism the rest of the language promises, extended to randomness. A repeatable test, a simulation you can bisect, a training run you can reproduce: all of them want exactly this. The state is a plain value you own and pass by address, the same visible-mutation marker as everywhere else — no ambient generator, no hidden global to make two tests interfere.

RangeInt draws from an inclusive range, Float from [0, 1), Next answers raw words. And the printed sum beside the shuffled line is the completeness check in this page’s spirit: rearranged, never lost.

One boundary, stated plainly: this generator is for simulation, testing and games. It is deliberately not cryptographic — key material comes from the platform’s own entropy door, not from here.

Try it

1. Change the seed. Seeded(8) — a different order, equally fixed. Rerun twice; it does not budge. Then put 7 back and watch the page’s exact line return.

2. Sort the shuffle. Add a second Sort(address ns); after the shuffle and print again: 1 3 4 7 8 9. Order and disorder are inverse verbs over one value, which is the page’s quiet point — neither is special, both are yours.

Next

Dynamic arrays for the container these verbs serve, and WYSIWYG slicing for pieces of shaped values. Every example lives in the tutorial repository.