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 from | An internal member of a kit |
|---|---|
| the kit's own source, in any of its namespaces | callable |
| the app that uses the kit | refused |
| another kit, including one that implements the kit's contract | refused |
a kit or an app that writes the kit's namespace …; line | refused — 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/orCore/— 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#
- Contracts between kits — an interface in a package, and its version — a contract between kits, and which changes to it need a major version
- type visibility (public / internal) —
publicandinternalon a type, and the defaults - Interfaces — a contract several types can satisfy — interfaces and default members
- class methods — member visibility on a class
- package.osy —
package.osy: what a package is