Summary#
use declares a capability your app depends on. It goes inside the app { } manifest block — the one
place a project says what it is built from:
app Shop {
model "model/**/*.osy";
use Osysharp.Memory; // depend on the Memory capability
use Osysharp.Ui@3; // depend on the UI kit, pinned to major 3
}A use is your app's dependency — the equivalent of a package reference. It provisions the capability (its
tables and types become part of your app) and, for a versioned kit, records which version you want. To actually
reference a capability's names in a file, add a using for it there.
Signature#
use Osysharp.Memory; // a platform capability — version-neutral
use Osysharp.Ui@3; // a kit — pinned to a major (@3 = any 3.x; @3.3 = ≥ 3.3 within 3.x; @3.4.1 = exact)use is only valid inside the app { } block. A version pin (@…) is only meaningful on a kit — pinning
a version-neutral platform capability (which rides the platform binary) is an error.
Description#
What a dependency does#
Declaring use Osysharp.Memory; makes the Memory capability part of your app: its entities and types are
provisioned, its features (here, semantic [Searchable] fields and Memory.Search) become available. Remove the
use and the capability — and everything that needs it — is gone. The manifest is the single, authoritative list
of what your app depends on.
A dependency has a price, and you can ask what it is. A capability that is part of your app puts its tables in
your database — so use is a decision with a number attached, not a free import. osy model reports that number,
per capability, and separately reports the floor every app carries whether it declares anything or not:
capabilities: Osysharp.Agents, Osysharp.Ui, Osysharp.Workflow
Osysharp.Agents — 15 tables in your database, 7 types
Osysharp.Ui — no tables, 8 types
Osysharp.Workflow — 7 tables in your database, 9 types
carried regardless (not declared, cannot be declined):
the core baseline — 2 tables
→ 2 tables before this app declares anything
brought in by a declaration you wrote:
Osysharp.Counters — 1 table — you declare a `Counter`
Osysharp.EventOutbox — 2 tables — you declare an `[On]` handler
brought in by a capability you declared:
Osysharp.Memory — 4 tablesFour groups, because they answer four different questions: what you chose, what you cannot decline, what a
line you wrote brought with it, and what arrived because something you chose depends on it. A capability that
contributes only classes — Osysharp.Ui above — costs nothing in the database at all.
The second group is as small as it can be: two tables. Osysharp.Continuation is there because await
surviving a suspension is a property of the LANGUAGE, and Osysharp.AppAdmission because the platform pausing an
app for migration is not a thing an app has standing to decline. Everything else — auditing, workflow, memory,
agents, storage, scheduling, and both budgets — is a capability you choose, and an app that chooses none carries
those two and its own tables.
The third group is the one with no use behind it. Some storage is not a dependency you declare but a consequence
of a declaration you already wrote: a Counter needs somewhere to keep the number it has reached, and
app.Secrets needs somewhere to keep the sealed value, an [On] handler needs an outbox for the events it hears, and a
grant needs somewhere to record the links taken back. Those tables arrive with the declaration and an app that never
wrote one does not have them — so the report names the LINE rather than a capability, because the line is what you
would change. (Taking the line out later keeps the table and its rows: a recompile is not where data is deleted.)
using vs use#
They are two different things, exactly as a C# project separates its package references from its imports:
| Where | What it does | |
|---|---|---|
use Osysharp.Memory; | inside app { } | the dependency — provisions the capability, pins a kit version |
using Osysharp.Memory; | at the top of any source file | the import — brings the capability's names into that file's scope |
A file that references a capability's names imports them with using, just like reaching any other namespace:
// model/note.osy
using Osysharp.Memory;
entity Note {
[Searchable] string Body; // the [Searchable] feature comes from the Memory capability
}If your app declares an app { } manifest, that manifest is authoritative for CAPABILITIES: a
using Osysharp.X; for a capability you did not use is an error — the same way C# rejects a using for an assembly
you never referenced. Add the matching use to the manifest to fix it. (A quick throwaway snippet with no manifest
at all is unconstrained — there, a using provisions on its own.)
What about using System.Linq;?#
The first lines of most C# files compile unchanged. The .NET namespaces whose types Osy# provides are accepted as
imports that change nothing — their types are always in scope, using or not — and need no use:
using | what it stands for here |
|---|---|
System | Convert, Math, Guid, DateTime, the common exceptions |
System.Linq | LINQ — over a list in hand and over an entity set alike |
System.Collections.Generic | List<T>, Dictionary<K,V>, HashSet<T> |
System.Text | StringBuilder |
System.Text.Json | JsonSerializer |
System.Text.RegularExpressions | Regex |
System.Net | WebUtility |
Any other .NET namespace — System.IO, System.Threading.Tasks, Microsoft.* — is refused by name: Osy# is written
like C# but is not .NET, so there is no assembly behind it to import, and it is not a capability to use either.
The refusal lists the accepted set above.
using System;
using System.Linq;
using System.Collections.Generic;
int Big(List<int> xs) => xs.Where(x => x > 10).Count();A bundled KIT needs no use — the using is enough#
Osysharp.Ui, Osysharp.MarkdownEditor, Osysharp.PdfViewer and Osysharp.BarcodeScanner ship inside the platform. There is
nothing to fetch and nothing to choose, so for those the using is the whole declaration — the kit composes for the
files that import it, and an app that never imports it pays nothing.
Osysharp.Chartsis a PACKAGE now, not a bundled kit: it lives atgithub.com/osysharp/charts, and an app that wants it writesuse Osysharp.Charts@1;in its manifest like any other dependency. The kits are becoming packages one at a time; each one that moves gains auseand loses nothing else. See package.osy.
Osysharp.Ui adds the other direction: one use Osysharp.Ui; in the manifest puts it in scope for EVERY FILE,
with no using written anywhere. It is the kit almost every app reaches for, and using is FILE-scoped — so a
per-file opt-in was not one line per app but one line per file, and the line you forget is in the file you wrote
last. Both spellings are legal and they answer different questions: use once for the project, using for one file.
⚠ What it is NOT is automatic. An app whose manifest references no kit does not get one — a package is fetched, and nothing can be fetched that the app never named. Name a kit control with neither spelling present and the refusal says which kit ships it and which two lines bring it in. (A throwaway snippet with no manifest keeps the kit: it has nothing to reference with, which is also why a doc example here can render a control without either line.)
The @version on a kit's use is a PIN, not a permission — the reference is the use itself:
app Shop {
model "model/**/*.osy";
use Osysharp.Ui@3; // the reference, plus a version pin; a bare `use Osysharp.Ui;` is the usual form
use Osysharp.Memory; // a CAPABILITY: declared for a different reason — it stands up a vector store
}The line between them is what the dependency DOES. A kit is syntax you import; a capability changes the shape of
your app — Osysharp.Memory a vector store, Osysharp.Storage a blob store, Osysharp.Observability audit tables — and
the manifest is where an app's shape is declared.
Version pins live on use#
A version belongs on the dependency, never on the import. use Osysharp.Ui@3; pins the kit; a @version written
on a using is an error that points you back to the use.
Importing static members and naming an alias#
using static System.Math; makes Math's members callable by their bare names in that file — Abs(-3), Max(a, b),
PI — and a function the file declares with the same name still wins, as in C#. using Sb = System.Text.StringBuilder;
names a type alias (any type since C# 12: using Point = (int X, int Y);). Both are FILE-scoped, as in C#.
using static System.Math;
using Sb = System.Text.StringBuilder;
int Spread(int a, int b) => Abs(a - b) + Max(a, b);
string Twice(string s) => new Sb().Append(s).Append(s).ToString();Examples#
// app.osy — the manifest declares the app's dependencies with `use`.
app Shop {
model "model/**/*.osy";
use Osysharp.Ui@3;
use Osysharp.Memory;
}// model/catalog.osy — a file imports what it references with `using`.
using Osysharp.Ui;
using Osysharp.Memory;
entity Product {
[Required] string Name;
[Searchable] string Description;
}See also#
- namespace — how a bare name resolves through the namespaces you import and the
Osyrincore. - Osysharp.Ui (the UI kit) — the UI kit you depend on with
use Osysharp.Ui;and import withusing Osysharp.Ui;. - Pinning a kit version (using Ui@3) — pinning a kit's major version on the
use.