Intents & services¶
Portable programs ask for outcomes, not devices.
This page explains the two ways a d/BASIC program talks to the machine underneath it, and why they let one compiled program run in a browser, on a desktop and on an 8-bit computer. After reading it you will know what an intent and a service are, how a frame is drawn, which families of requests exist, and what happens when a machine cannot do what was asked.
A d/BASIC application never needs to know which video chip, GPU, operating system, bank switch, sound device or browser API sits underneath it. It says what it means. The d/OS runtime, the program that runs your compiled code, adapts that meaning to the machine in front of it.
That is the why behind intents. An intent is a named request, such as "fill this rectangle" or "play this tone", that the machine carries out however it can.
The old portability trap¶
Classic BASIC made it delightfully easy to reach the machine:
That immediacy was exciting, but the address was the machine. Move the program to another computer and its meaning vanished.
d/BASIC moves the boundary up one level:
This says "fill this rectangle". It does not say which processor does the filling, how pixels are stored, whether a GPU draws it, or how a black-and-white screen represents the color.
The adaptive runner¶
The runtime has three jobs:
- Check the exact operation and its version before trusting the program.
- Choose a route that suits this host.
- Keep the meaning while making the implementation richer or simpler.
Upgrade on a richer system¶
A browser or modern desktop can improve presentation without changing the program:
- draw a standard text role with a real browser or desktop font, at the display's full resolution;
- expand color onto a deep-color GPU surface;
- run a pure arithmetic expression as one batched operation on a coprocessor or vector unit;
- keep clipping and geometry in logical d/BASIC coordinates while drawing into a high-density surface;
- use hardware composition to present the frame.
This is why the playground's d/Works text (d/Works is the office suite being written in d/BASIC: d/Write, d/Calc, d/Present) can use Atkinson Hyperlegible and JetBrains Mono instead of magnifying a tiny bitmap font. The source still issues the same text intent with the same logical geometry.
Lower on a constrained system¶
A small d/OS machine can keep the same meaning by a different route:
- quantize or dither color to the palette the screen actually has;
- draw a text role with the built-in font whose metrics match;
- run a bulk operation in bounded slices so the machine stays responsive;
- expand one portable arithmetic batch into ordered single MATH steps when there is no batch accelerator;
- compose the frame through the local display instead of a desktop GPU.
"Lower" does not mean "do something vaguely similar". The runtime must keep ordering, bounds, clipping, object state, result shape and the all-or-nothing nature of each operation. If it cannot keep those promises, it declines and says why.
One source, honest differences¶
| Concern | Program owns | Runtime may adapt |
|---|---|---|
| drawing | logical coordinates, clip, color role, text, ordering | raster method, font rasterizer, color representation, composition path |
| math | type, expression order, rounding rules | local scalar work, batching, coprocessor crossing |
| arrays | type, rank, bounds, all-or-nothing operation | vector route, chunking, storage tier |
| windows | application model and lifecycle | native window, browser surface, d/OS composed surface |
| unavailable work | the requested meaning | a clear error naming what is missing, never a fake success |
Two outward-call spellings¶
INTENT DOMAIN.OP(...)¶
An intent names a versioned operation in a domain, a family such as graphics or sound:
INTENT GFX.BEGIN_FRAME()
INTENT GFX.FILL_RECT(0, 0, Width%, Height%, Background%)
INTENT GFX.DRAW_TEXT(12, 12, "READY", Font%, Foreground%, Background%)
INTENT GFX.PRESENT()
The compiler looks up the domain, the operation name, the argument count and the argument types in the generated registry, the official list of every intent. Names are not case-sensitive; numeric domain and operation codes never appear in source.
SERVICE ROW(...)¶
A service is a small, immediate request to the runtime or the operating system, identified by one globally named row in a table:
Use services for the small local matters around the program: window title, asking for a repaint, console primitives, time and process context. Use intents for versioned capability families such as graphics, compute, data, the pasteboard and drag sessions.
Prefer the friendly projection
You normally write PRINT, TIMER, SQR or a typed d/Works data wrapper rather than calling their low-level service or intent rows yourself. The generic syntax is the escape hatch that makes every registered row reachable without adding a new keyword.
A complete portable frame¶
DIM SHARED Width AS INTEGER
DIM SHARED Height AS INTEGER
WINDOW SUB OPEN()
Width = 320
Height = 192
SERVICE SET_TITLE("Intent postcard")
SERVICE INVALIDATE()
END SUB
WINDOW SUB DRAW()
INTENT GFX.BEGIN_FRAME()
INTENT GFX.FILL_RECT(0, 0, Width, Height, 2081)
INTENT GFX.SET_CLIP(8, 8, Width - 16, Height - 16)
INTENT GFX.DRAW_TEXT(12, 14, "ONE PROGRAM. MANY HEADS.", 3, -1, 2081)
INTENT GFX.RESET_CLIP()
INTENT GFX.PRESENT()
END SUB
WINDOW SUB RESIZE(W AS INTEGER, H AS INTEGER)
Width = W
Height = H
SERVICE INVALIDATE()
END SUB
WINDOW SUB CLOSE()
END SUB
The resize handler receives the runtime's new logical canvas. The application lays itself out again and asks for a frame; it does not assume that a bigger desktop window is just a stretched 320 × 192 bitmap.
Frame discipline¶
The usual GFX frame is:
BEGIN_FRAME- zero or more drawing calls
PRESENT
Clips are explicit and nest in your program's logic, not in hidden canvas state. PRESENT completes the frame; an accelerated queue merely accepting the work is not the same as the frame being shown.
SERVICE INVALIDATE() asks the host to schedule WINDOW SUB DRAW(). It does not paint straight away. That keeps event handling and drawing separate and lets the host merge repaint requests.
Registered GFX vocabulary¶
Signature notation below uses I = INTEGER, L = LONG, S = STRING, and A = a whole array passed as a block of bytes.
| Intent | Arguments | Purpose |
|---|---|---|
GFX.QUERY_VIEWPORT |
A |
query the current logical viewport |
GFX.BEGIN_FRAME |
none | begin one frame |
GFX.PRESENT |
none | present the frame |
GFX.SET_CLIP |
I, I, I, I |
set x, y, width, height clip |
GFX.RESET_CLIP |
none | restore the full clip |
GFX.FILL_RECT |
I, I, I, I, I |
fill a rectangle with a standard color value |
GFX.DRAW_TEXT |
I, I, S, I, I, I |
draw text at x, y with font and color roles |
GFX.BLIT_RESOURCE |
A, I × 8 |
draw a bounded bitmap from a caller's array; not a packaged asset lookup |
GFX.BEGIN_SURFACE_MOVE |
I, I, A |
begin moving a surface |
GFX.MOVE_SURFACE |
I, I |
update the move position |
GFX.END_SURFACE_MOVE |
none | complete the move |
GFX.PRESENTATION_HINT |
I, I, I, A |
publish presentation hints |
GFX.COPY_RECT |
I × 6 |
copy sx, sy, w, h to dx, dy |
GFX.POLYLINE |
A, I, I, I |
draw a packed line record |
GFX.DRAW_TEXT_STYLED |
I, I, S, I, I, I, I |
draw text with a registered style role |
Use SET_CLIP around text and widget content that must not spill into neighboring surfaces. A rich host may draw a smoother font, but it must still honor the clip.
Intent domains¶
| Domain | The question it answers |
|---|---|
CORE |
What can this host do, and how do I fence or cancel work? |
GFX |
What should appear on this surface? |
AUDIO |
What should be heard? |
COMPUTE |
What bounded bulk computation should be performed? |
AI |
What assistive proposal or analysis is requested? |
UI |
What higher-level user-interface meaning is being expressed? |
SERVICE |
What exchange with the system, such as pasteboard, schema lookup or drag, should occur? |
MATH |
What standard arithmetic, conversion, formatting or array job is required? |
FILE |
What operation should occur on bytes at a named mount and path? |
DATA |
What database identity, query, revision, or durable artifact operation should occur? |
The registry, the official list of intents, has a fixed set of domains and generates each row's signature. Adding a row changes the catalog, not the grammar of the language.
See Resources, Images & Sound for packaged image forms, font roles, tones and the PCM lifecycle. Networking uses the same boundary through the owning dworks.network objects over SERVICE.NETWORK_* rows; see Networking.
Core and compute rows¶
| Intent | Signature | Meaning |
|---|---|---|
CORE.NOP |
() |
do nothing, on purpose |
CORE.QUERY_CAPABILITIES |
(A) |
fill a bounded array describing what the host can do |
CORE.CANCEL |
(L) |
cancel an operation by its ticket |
CORE.FENCE |
() |
order prior work before later work |
CORE.QUERY_CLOCK |
(A) |
fill a standard clock record |
COMPUTE.VECTOR_I16 |
(I, L, A, A, A) |
bounded 16-bit vector computation |
COMPUTE.SHA256 |
(I, A, A) |
hash an exact number of bytes from one array into a digest array |
Typed libraries such as dworks.sha256 hide the array bookkeeping:
Math is also an adaptive Intent family¶
The familiar expression stays the way you write it:
The compiler recognizes an expression that is pure arithmetic of one type and may package it as one portable MATH.EVAL program. A capable runtime evaluates it in a single crossing. A simpler one expands it into the same ordered MATH.MUL, MATH.ADD and MATH.SQR steps. Calls, conversions, comparisons, RND, TIMER and other points where an effect could be observed split a batch.
The registered MATH vocabulary covers:
- scalar
ADD,SUB,MUL,DIV,NEG,ABS,SGN,CMP, andPOW; SQR,LOG,EXP,SIN,COS,TAN, andATN;- standard
RNDandSEED; - numeric
FORMAT,PARSE, andCONVERT; ARRAY_MAPandARRAY_REDUCE; andQUERY_CAPSand batchedEVAL.
This is a performance model that a 6502 (the processor in the Atari 800, the Commodore 64 and the Apple II) and a desktop can share: cross the boundary less often when you can, and keep the order of operations always.
Files, databases, pasteboard, and drag use packed records¶
These families exchange records packed into bounded integer arrays. Packing them by hand is allowed but rarely wise. d/Works libraries provide named types and procedures around the wire format.
FILE workflows¶
The FILE family is filesystem manipulation: QUERY_MOUNT, LIST, STAT, OPEN, READ, WRITE, CLOSE, and EDIT. EDIT selects delete, trash, restore, rename, same-mount move, or directory creation. It works with explicit mounts and paths; it does not grant database access or invent revisions. See Files & File Manipulation.
DATA workflows¶
The DATA family is d/BASIC's database. It works with identities, typed values, stable snapshots, writes, attachments, revisions and receipts (a receipt is the host's record of exactly what a committed operation did); it is unrelated to the classic embedded DATA statement.
The registry groups DATA rows by task:
- capability and read:
QUERY_CAPS,OPEN,GET_VALUE,CLOSE; - snapshots:
OPEN_SNAPSHOT,FETCH_PAGE,RESOLVE_ROW,REVALIDATE_OBJECT,ACCEPT_EXACT,CLOSE_SNAPSHOT; - writes and attachments:
QUERY_WRITE_CAPS,OPEN_WRITE,BEGIN_WRITE,BEGIN_ATTACHMENT,WRITE_ATTACHMENT_CHUNK,FINISH_ATTACHMENT,COMMIT_WRITE,WRITE_STATUS,ABORT_WRITE,CLOSE_WRITE; - artifacts:
QUERY_ARTIFACT_CAPS,BEGIN_NEW,BEGIN_SAVE,BEGIN_SAVE_AS,BEGIN_PUBLISH,WRITE_ARTIFACT_CHUNK,FINISH_ARTIFACT,COMMIT_ARTIFACT,ARTIFACT_STATUS,ABORT_ARTIFACT,CLOSE_ARTIFACT,ACK_ARTIFACT_RECEIPT; - browsing and retirement:
ALLOCATE_ARTIFACT_OPERATION,LIST_ARTIFACTS,OPEN_ARTIFACT_READ,READ_ARTIFACT_CHUNK,CLOSE_ARTIFACT_READ,BEGIN_RETIRE,LIST_PUBLICATIONS,OPEN_PUBLICATION_READ.
See Database & Data Intents for the full lifecycle and examples.
SERVICE-domain workflows¶
- pasteboard: query, begin, write, exact-length write, commit, abort, inspect, list, negotiate, read, status, and acknowledge;
- DOBJ schemas (DOBJ is the typed object a program hands to another program when you drag, drop, copy or paste): length and read;
- drag: query, begin, negotiate, accept/reject, destination commit, authorize move, source commit, status, cancel, and acknowledge.
The workflow names make ownership visible. "Begin, stage, commit, acknowledge" is deliberate: a transfer between applications should not become real merely because a pointer crossed a rectangle.
Local Service rows¶
The runtime's service table supplies these families:
| Family | Rows |
|---|---|
| process | ARGUMENT_COUNT, ARGUMENT_TEXT, INSTANCE_ID, SLEEP_MS |
| console | WRITE_TEXT, WRITE_NEWLINE, WRITE_COLUMN, WRITE_SPACES, WRITE_ZONE, READ_LINE, READ_KEY, CLEAR, LOCATE, COLUMNS, ROWS |
| time | MONOTONIC_MS, MONOTONIC_GRADE, WALL_STATE, WALL_HHMM, TIMER_SECONDS |
| surface | WIDTH, HEIGHT, SET_TITLE, INVALIDATE |
Language conveniences map onto these rows. PRINT uses console output; TIMER reads timer seconds; the host supplies the RESIZE dimensions. Direct SERVICE statements are most useful for rows that do something, such as SET_TITLE and INVALIDATE; rows that return a value normally appear through the language feature built on them.
The checks a program passes before it runs¶
A compiled program file, .dbc, declares what it requires. Before its first byte runs, the loader validates the file and checks that this host offers compatible service and intent rows. A program therefore cannot draw half a window and only then discover that the display route it needs never existed.
While running, an intent with a ticket can answer Pending; the runtime pauses that operation and the host resumes it in a later bounded turn. Program order is preserved while the event loop, the browser or the small machine stays responsive.
Saying no is the final portability feature¶
There are only two honest outcomes for a capability request:
- the host performs the registered meaning; or
- it declines with a stable class, an error code and a detail message.
There is no third path where an unknown request is ignored or the host quietly changes the program. ON REFUSAL lets an application recover when the capability was genuinely optional. See Compatibility, Migration & Refusals.
Rules for portable application code¶
- Ask for outcomes, never device registers.
- Query capabilities when more than one honest experience is possible.
- Treat geometry, event order and array bounds as promises.
- Prefer typed d/Works wrappers for complex array records.
- Let the runtime upgrade or lower presentation; do not write per-target branches in BASIC.
- Handle an optional capability being declined deliberately. A required one being declined should stop the program loudly.
Next: Drag, Drop & DOBJ →
See also: Windows & Events · Widgets · Resources, Images & Sound · Networking · Drag, Drop & DOBJ · Compiler & Optimizer · Bytecode & Delivery