Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Stdlib

Random.* — an ordinary random number

int Random.Next() · Random.Next(max) · .OrderBy(x => Random.Next()) — works in LINQ

A random integer for ordinary work — picking a row, jittering a retry, shuffling. `Random.Next(10)` answers 0..9. It WORKS INSIDE A LINQ QUERY and translates to SQL, so `.OrderBy(f => Random.Next())` is one round trip and `.ThenBy(f => Random.Next())` is a random tiebreak. It is SEEDABLE and therefore reproducible, which is why it must never produce a token: `Security.RandomId` is the unguessable one.

stable1 example compiled by CIrandomstdlibsecuritytesting

Summary#

Random.Next answers a random integer, spelled exactly as C#'s System.Random.Next.

int n = Random.Next(10);        // 0..9   — max is EXCLUSIVE, as in C#
int d = Random.Next(1, 7);      // 1..6   — min inclusive, max exclusive

There are two randoms in this platform and choosing between them is the whole of what you need to know:

you wantusewhy
a number, a pick, a shuffle, a jitterRandom.Nextordinary, fast, and reproducible under a test seed
a token, a reset code, an api key, a session idSecurity.RandomId / RandomHexcryptographic — see Security.* — hashing, verifying, tickets, random ids

Signature#

int  Random.Next()                   // any non-negative int — the ordering form
int  Random.Next(int max)            // [0, max)   — `max` must be at least 1
int  Random.Next(int min, int max)   // [min, max) — `max` must be greater than `min`

An empty range has no value to answer with, so it is refused rather than answered: Random.Next(0) and Random.Next(5, 5) both throw, naming the bound. Random.Next(list.Count) over an empty list is the usual way to reach that, so check the count first.

Description#

It is seedable, and that is not an implementation detail. A test that draws must be able to draw the same sequence twice, or it can only assert statistically — "at least 25 of 40 were idle" — which is slow and flaky by construction. Seeding is what makes an exact assertion possible.

And that is exactly why it must not make a secret. A value anyone can reproduce is not unguessable. The sequence is predictable from any earlier value, and nothing about the result looks wrong: it is not obviously sequential, the tests pass, and it stays guessable until somebody enumerates it. C# draws this same line between System.Random and RandomNumberGenerator, and gets the same misuse.

security-weak-random is a MUST-tier lint on exactly that mistake — a Random draw landing in a member named for a credential (token, secret, password, apiKey, nonce, otp, …). It fires on the DESTINATION, never on the call, because Random.Next is correct nearly everywhere.

It works inside a LINQ query#

Random.Next() is translated to SQL, so it is usable anywhere in a query — not only in a function body. There is no separate OrderByRandom() verb to learn, and none is needed: it is an ordinary OrderBy over an ordinary call, which is what a C# author writes, and it therefore composes with ThenBy, Where, Take and the rest exactly as any other sort key does.

This is how you take one row at random without a Count() and a Skip():

// one row at random — ONE round trip
Film any = Film.OrderBy(f => Random.Next()).Take(1).FirstOrDefault();

// the shape most selection rules actually take: least-compared, RANDOM AMONG TIES
Film pick = Film.OrderBy(f => f.Comparisons)
                .ThenBy(f => Random.Next())
                .Take(1).FirstOrDefault();

The second is the one worth knowing. Without a random tiebreak, "the least-compared film" returns the same film every time two are tied, so a matchmaker walks the same pair repeatedly. With it, the primary sort still decides and the tie is broken fairly, in one query.

It runs in the DATABASE, not in the browser and not in memory — ORDER BY random() — so the whole draw is one round trip whatever the table's size. A .Where(…) before it narrows the rows the database is choosing among, as you would expect:

Film pick = Film.Where(f => !f.Watched)
                .OrderBy(f => Random.Next())
                .Take(1).FirstOrDefault();

Not inside a live var. A reactive read re-runs whenever its inputs change, and a random order returns a different row each time — so the value flickers when something unrelated moves. Draw in an action, store what you drew, and let the page read the stored row.

Examples#

entity Card { [Required, MaxLength(40)] string Face;
  security { allow read, create when IsAnonymous || IsAuthenticated; } }

// One of a known set, chosen at random.
string DealOne() {
  var faces = ["clubs", "diamonds", "hearts", "spades"];
  return faces[Random.Next(faces.Count)];
}

// A retry jitter — spread out so a hundred clients do not return at the same instant.
int BackoffMillis(int attempt) { return 500 * attempt + Random.Next(250); }

See also#

Related

Security.* — hashing, verifying, tickets, random ids

The calls an authentication flow needs: `HashPassword` (salted, one-way), `VerifyPassword` (constant-work comparison…