Osy#betaRun it on Osyrin: osyrin.com

Reference / Types

type visibility (public / internal)

entity T { … } · internal entity T { … } · public class T { … } · enum E { … }

A top-level declaration carries a public or internal visibility that decides whether code outside its package can name it. The default depends on what you declared: an entity, enum, component and control are public, a class is internal (exactly C#).

stable1 example compiled by CItypesvisibilityauthoring

Summary#

Every top-level type has a visibility that decides whether code outside its package can name it. A public type is part of the surface its package offers outward; an internal type is an implementation detail, usable freely inside its own package — the app, or the kit — 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 and a control are public too — internal is how a package keeps a helper component or a shim it only uses itself off the surface it offers.

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 package
public class Money { … }                   // a class offered outward
component Badge(string label) { … }        // public — a component is part of its namespace's surface
internal component Chevron() { … }         // a helper a package keeps to itself
internal control Gauge { … }               // …and the same for a foreign-ABI shim

Description#

The defaults, and why they differ#

You declareDefaultWhy
entitypublicAn entity is the app's data surface — its fields are already public, so the type is too.
enumpublicAn enum is vocabulary: it appears as the field type of a public entity, so an internal default would create friction at every use.
classinternalExactly C#. A class stays source-portable — it must lift into an external C# project verbatim, so its rules follow C#'s without deviation.
componentpublicA component is part of what its namespace offers — which is what makes a package's components usable at all. Write internal for a helper you do not want callers to reach.
controlpublicSame, for the same reason: a control's whole surface is its control block, so a package that could not keep a shim in would publish every one it declares.

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. internal means the package — exactly as C#'s means the assembly. An internal type cannot be named from outside the package that declares it, and using SomeNamespace; of another package brings only that namespace's public types into scope. This is how a published unit distinguishes what it offers from what it merely uses.

A package is what package.osy declares, and an app's own source is one package too. So a kit split over several namespaces shares its internal types, functions and members between them; inside an app, internal does not separate one namespace from another; and another kit — or an app — that writes a kit's namespace …; line is still outside it. The same holds for an internal function and an internal member, which is how a kit keeps a call to itself; see internal — a member only its own package may call.

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` explicitly

Visibility and authorization answer DIFFERENT questions#

A component has both, and conflating them is the mistake worth naming. Visibility decides who may reference the declaration — a compile-time question, about code. Authorization decides who may view the rendered page — a runtime question, about people: 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.

So internal component does not mean "signed-in only", and [AllowAnonymous] does not make a component referenceable from another namespace. You will usually write neither: a component is public by default and [Composable]/[Route] carry the authorization story.

// inside a package
public component Card(string title) { render { … Chevron(); … } }   // the surface
internal component Chevron() { render { … } }                      // its business

An app that imports that package may render Card; naming Chevron is refused, and so is One.Kit.Chevron(…) — the qualified spelling reaches a namespace's surface, not past it.

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 package — 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#

Related

constructor

A class declares one constructor — its name is the class name, it takes no return type, and it runs when you write new…

class methods

Behaviour attached to a class — a method with a receiver, called as value.Method(). Classes are in-memory values, so a…

component

The one archetype for all UI: a bounded reactive unit — typed props, reactive members (fields, `live`…

namespace

Declares the namespace a file's types belong to, written once at the top of the file. It is optional — a file without…

internal — a member only its own package may call

A function, a class member or a contract member declared internal is callable only from the package that declares it…