A reckoner seed: isam, whole-table words only — machines/seeds/seedisam.shoddy
seedisam bridges isam, the machine
for indexed tables. It has two entry points that register the same
word names. A mill folds one or the other, never both, so a
session learns one vocabulary.
RckSeedIsamNum / RckSeedIsamStr
take a table the host program has already opened. The table is
closed over inside the words they register: the words hold it privately,
and it is never pushed onto the stack. A form field or an embedded
scripting layer seeds the engine this way, with a table it already knows
about. These entry points register whole-table words only:
ISAMALL ISAMRANGE ISAMHAS ISAMGETOR ISAMCOUNT.RckSeedIsam takes nothing. It registers
an ISAMOPEN that opens a table from a path, a schema and the
name of its key, all typed at the prompt. (A schema is a list that names
each field and says what kind of value it holds.) This is what
halifax folds.This page used to say ISAMOPEN could not
exist. The reason given was that a handle — the number a
program holds to name an open file — must never reach the stack. A
handle is a NUMBER, and UNDO restores the stack.
So the number naming an open table would come back with it. That was one
of two problems, and naming them apart is what let both be
solved.
UNDO does not
touch, with CLOSE and BOUND over it.
ISAMOPEN binds rather than pushes. Nothing a session can type
ever sees a number.Isam carries
Rd, Wr and KeyOf — reader,
writer and key functions over the caller's own Type,
compiled in. A session has to be told a layout instead, and that
is exactly what seedrecio's schema is. This
seed borrows that schema rather than inventing a second one.One place the types genuinely fight back.
isam orders keys with a raw <, so
the key type is fixed when the program is compiled. But the schema that
says whether the key is a number or a string is data, read at run time.
So both instantiations exist in the seed, held in one sum type (a value
that is exactly one of a fixed set of shapes). Every word branches once on
which one it holds. It reads like duplication. It is the language stating
a fact.
Two entry points, not one generic one.
isam.shoddy's keys must be NUMBERs or
STRINGs. Shoddy has no way to ask a Cell which
of the two it holds and hand back a value of the matching generic type.
So a number-keyed table seeds through RckSeedIsamNum, and a
string-keyed one through RckSeedIsamStr. Both register the
same five words.
Records cross the bridge through a cellOf function the
caller supplies, not through a new stack case. isam's record type is the
caller's own Type, unknown here exactly as it is unknown to
isam.shoddy itself. The usual shape to hand back
is a Pair built field to field, as
seedcsv's CSVPAIRS already does
for a row.
Let db = IsamOpen("customers.dat", "customers.idx", KeyOf)
Let st0 = RckSeedIsamNum(RckNew(), db, Fn(rec) => CutPair(Pair(CutNum(Id(rec)), CutStr(Name(rec)))))
RckEval(st0, "ISAMCOUNT") ' x: however many records the table holds
RckEval(st0, "100 200 ISAMRANGE") ' x: the records with keys 100..200
RckEval(st0, "999 " & Chr(34) & "none" & Chr(34) & " ISAMGETOR") ' x: "none" unless key 999 exists
The same five words for both key kinds; NUMBER-keyed via
RckSeedIsamNum, STRING-keyed via RckSeedIsamStr
| Word | Description |
|---|---|
| ISAMALL ( -- list ) | Every record in the table, key order. |
| ISAMCOUNT ( -- n ) | How many records the table holds. |
| ISAMHAS ( k -- flag ) | Whether the table has a record under key k. |
| ISAMRANGE ( lo hi -- list ) | The records with keys from lo to hi inclusive, key order. |
| ISAMGETOR ( k dflt -- rec ) | The record under key k, or dflt unchanged when there is none. |
RckSeedIsamEvery word takes the name the table was opened under. A record is a list of values in schema order, as for RECGET.
| Word | Description |
|---|---|
| ISAMOPEN ( path schema key name -- ) | Open an indexed table and keep it open under that name. The schema is a list of { name kind } specs, and key names which field is the key. Makes the table if it is not there. CLOSE shuts it — one name, two files. |
| ISAMCOUNT ( name -- n ) | How many records the table holds. |
| ISAMFIELDS ( name -- list ) | The field names of that table's schema, in record order. The key is one of these. |
| ISAMHAS ( name k -- flag ) | Whether the table has a record under key k. |
| ISAMGETOR ( name k dflt -- rec ) | The record under key k, or dflt unchanged when there is none. There is no plain ISAMGET: IsamGet aborts on a missing key, and a bridged word may not end the session. |
| ISAMALL ( name -- list ) | Every record, in key order. |
| ISAMRANGE ( name lo hi -- list ) | Every record whose key lies from lo to hi, in key order. |
| ISAMINSERT ( name rec -- ) | Add rec. Refuses when that key is already there — ISAMUPDATE is the one that replaces. |
| ISAMUPDATE ( name rec -- ) | Replace the record with rec's key. Refuses when there is none. |
| ISAMDELETE ( name k -- ) | Remove the record under key k. Refuses when there is none. |
Every one of those refusals is a pre-flight: a check made
before the risky call. IsamInsert aborts on a duplicate key.
IsamUpdate, IsamDelete and IsamGet
abort on a missing one. So IsamHas is asked first each time,
and that is the whole reason these words are reachable from a prompt at
all. The key is checked against the schema's kind too: a string key handed
to a number-keyed table would not fail, it would quietly look up record
0.
| User | How | |
|---|---|---|
| halifax | The calculator's table words, through RckSeedIsam — a table the session opens for itself from a path, a schema and the name of its key. | |
| sparky | Sparky folds it too, so a model calling eval reaches the same words halifax puts at a prompt. |
A host with a table of its own seeds the other half directly. It calls
RckSeedIsamNum or RckSeedIsamStr with a handle
it has already opened. A mill folds one entry point or the other, never
both: the word names are shared on purpose, so a session learns one
vocabulary.
| Machine | Why | |
|---|---|---|
| cuttle | The Cell type records cross the bridge as. | |
| isam | The domain this seed bridges: IsamAll, IsamCount, IsamHas, IsamRange, IsamInsert, IsamUpdate, IsamDelete — and, in the session-opened half, IsamOpen. | |
| reckoner | RckReg, RckSeeding and the argument readers every registered word is built from — and the named-resource table, RckBind and RckResOf, that makes an open table reachable after UNDO. | |
| seedrecio | The schema language, and its reader, writer and row checks. One definition of what { "who" "str" 12 } means, used by both record machines, so the two cannot drift apart. | |
| seq | List plumbing under the schema and key lookups. | |
| str | Join, so a key naming no field is refused with the field names there actually are. |