Summary#
Every top-level type has a visibility that decides whether code outside its namespace can name it. A
public type is part of the surface its namespace offers outward; an internal type is an
implementation detail, usable freely inside its own namespace and invisible beyond it.
You rarely have to write the modifier, because the default follows what you declared: an entity or an
enum is public, a class is internal. A component has no visibility modifier at all.
Signature#
entity Product { string Name; } // public — an entity is a data surface
enum Status { Draft, Active } // public — an enum is vocabulary
class Money { public decimal Amount; } // internal — exactly C#
internal entity Ledger { … } // an entity kept inside its namespace
public class Money { … } // a class offered outward
component Badge(string label) { … } // no modifier — see belowDescription#
The defaults, and why they differ#
| You declare | Default | Why |
|---|---|---|
entity | public | An entity is the app's data surface — its fields are already public, so the type is too. |
enum | public | An enum is vocabulary: it appears as the field type of a public entity, so an internal default would create friction at every use. |
class | internal | Exactly C#. A class stays source-portable — it must lift into an external C# project verbatim, so its rules follow C#'s without deviation. |
component | (none) | A component's access is governed by authorization, not visibility. See below. |
An explicit public or internal always overrides the default. private is not a top-level modifier — C# has
no private top-level types, and neither does Osy#.
What visibility controls#
Visibility is a hard access rule, not a decoration. An internal type cannot be named from outside its
namespace, and using SomeNamespace; brings only that namespace's public types into scope. This is how a
published unit distinguishes what it offers from what it merely uses.
Because an entity and an enum default to public, a unit that means to keep one to itself must say so:
entity Product { … } // exposed to anyone who imports this namespace
internal entity PriceHistory { … } // an implementation detail — say `internal` explicitlyA component has no visibility#
Writing public component or internal component is an error. A component's reachability is decided on a
different axis — authorization: a routed component requires an authenticated caller unless it is marked
[AllowAnonymous], and [Composable] governs whether it may be rendered inside another component's surface.
Type visibility would be a second, redundant gate answering a question authorization already answers, so a
component simply doesn't have one.
Entity fields are always public#
A visibility modifier on an entity field is an error — the field is the data, so it is always public. A
class member is different: it carries its own public/private member
visibility, and a bare member is private, exactly as in C#.
Examples#
/// A catalog item other code may reference. `entity` is public by default.
entity Product {
[Required] string Name;
decimal Price;
}
/// An internal roll-up used only inside this namespace — say `internal` to keep it in.
internal entity PriceHistory {
Product Item;
decimal Was;
}
/// A class is internal by default (C#); mark it `public` to offer it outward.
public class Money {
public decimal Amount;
public string Currency;
}See also#
- namespace — the namespace a type lives in, and what
internaltherefore keeps it inside of. - constructor — member visibility (
public/private) on class members, the other visibility axis. - component — why a component's access is an authorization question, not a visibility one.