Osy#betaRun it on Osyrin: osyrin.com

Reference / Project

internal — a member only its own package may call

public interface IProvider { internal string Complete(string prompt); } · internal string Record(string key, int units) { … }

A function, a class member or a contract member declared internal is callable only from the package that declares it. Any package may implement a contract's internal member; only the contract's package calls it. An app or another kit that calls it is refused at compile time, by the member's name and the package's.

stable1 example compiled by CIprojectpackageskitscontracts

Summary#

internal on a function or a member means only the package that declares it may call it. The app's own source counts as one package; each kit is another.

It is what lets a kit stand in front of something. A kit that meters calls to a provider declares the provider's contract with an internal member: other kits implement it, and only the metering kit calls it — so every call goes through the kit's own public function, which records it. A payment provider behind a ledger and a mail carrier behind an outbox are the same shape.

/// Something that answers a prompt. Any package may implement it; only this one calls `Complete`.
public interface IProvider {
  string Key { get; }
  internal string Complete(string prompt);
}

/// This package's own write: who answered, and how much.
internal string Record(string key, int units) { return key + ":" + units; }

/// The one public way to a provider — it records every call it makes.
public string Ask(IProvider provider, string prompt) {
  var answer = provider.Complete(prompt);
  return Record(provider.Key, answer.Length) + "|" + answer;
}

/// A provider answers the internal member with an internal member of its own.
public class EchoProvider : IProvider {
  public string Key => "echo";
  internal string Complete(string prompt) => "echo " + prompt;
}

string Try() { return Ask(new EchoProvider(), "hi"); }   // "echo:7|echo hi"

Signature#

// package Acme.Meter
public interface IProvider { internal string Complete(string prompt); }   // implemented anywhere, called only here
internal string Record(string key, int units) { … }                       // called only here
public string Ask(IProvider provider, string prompt) { … }                // what everyone else calls

// package Acme.Fast          (use Acme.Meter@0;)
public class FastProvider : IProvider { internal string Complete(string prompt) { … } }

Description#

Who may call it?#

Code written in the same package as the declaration — whichever of the package's namespaces it is in, as C#'s internal is the assembly. A package is the unit package.osy declares; an app's own source is one too, so inside an app internal does not separate one namespace from another.

Calling fromAn internal member of a kit
the kit's own source, in any of its namespacescallable
the app that uses the kitrefused
another kit, including one that implements the kit's contractrefused
a kit or an app that writes the kit's namespace …; linerefused — a namespace is a line anyone may write; the package is not

The refusal names the member and the package:

'Acme.Meter.IProvider.Complete' is internal to the package `Acme.Meter` — it is only callable from code in that package.
`Record` is `internal` to the package `Acme.Meter` — only code in that package may call it, so it is not part of what
that code offers. Only its `public` declarations are reachable from here.

How does another package implement an internal contract member?#

By declaring the member internal itself. The contract's package still reaches it, through the contract; the implementing package may call its own member; nobody else can.

public class FastProvider : IProvider {
  public string Key => "fast";
  internal string Complete(string prompt) { … }     // not `public`
}

Declared public, the implementation would be callable by everyone holding a FastProvider — around the package the contract belongs to — so it is refused where it is written. An override of an internal method stays internal for the same reason.

'Acme.Fast.FastProvider.Complete' answers 'Acme.Meter.IProvider.Complete', which is `internal` — only the package that
declares 'Acme.Meter.IProvider' may call it. Declared `public` here, it would be callable around that package. Write
`internal` on 'Acme.Fast.FastProvider.Complete' too: …

Is there another way to reach it?#

No. The rule is applied where a call is built, so the spelling does not matter:

  • the qualified name (Acme.Meter.Record(…)), the function as a value (Func<…> f = Record;), a lambda, a page's action;
  • a subclass written in another package (class Mine : FastProvider { … Complete(…) … }, base.Complete(…)) — an inherited internal member is still its declarer's;
  • a test: Record.Stub(…) replaces the function for everything that calls it, so an internal function is no more another package's to stub than to call. A kit's test app tests the kit through its public functions.

Two names are refused for the same reason:

  • a function whose name begins with two underscores (__Anything) — those names are the compiler's own, and it trusts some of them by name;
  • an app source file under Capabilities/ or Core/ — that is where the compiler places the files of the packages an app uses, and a file there would be read as that package's code. An app's source lives anywhere else.

What does the kit's surface show?#

osy kits <Kit> --surface lists a contract's internal member as internal — a class answers it, nobody outside the kit calls it — and does not list an internal function at all:

contract  IProvider   interface IProvider { internal Complete, Key }

For versions, an internal contract member is still something every implementor owes: adding one without a default is a major version (Contracts between kits — an interface in a package, and its version). It is never part of what a caller can name.

See also#

Related

Contracts between kits — an interface in a package, and its version

A kit that needs something done declares an ordinary public interface; another kit implements it; the app picks one in…

type visibility (public / internal)

A top-level declaration carries a public or internal visibility that decides whether code outside its package can name…

Interfaces — a contract several types can satisfy

An `interface` declares what a type must do without saying how — methods and property contracts, and no state. A member…

package.osy

The manifest that makes a git repository a publishable Osy# package. It names the package, says which of the…

class methods

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