Osy#betaa language · its runtime Osyrin · a hosted platform
Why Osy#Built for agentsAgents as declarationsWorkflows that waitRuns exactly onceSecure by defaultNothing to mockThe editor is the compilerUI in the languageDocuments are dataOne program

Reference / Class

Interfaces — a contract several types can satisfy

interface <IName> { <T> <Method>(<params>); <T> <Property> { get; } } class <Name> : <Base>, <IName> { … }

An `interface` declares what a type must do without saying how — methods and property contracts, no bodies and no state. A class may implement several of them alongside its base class, a value typed as the interface accepts any implementor, and the call runs the implementation the value actually holds.

stable6 examples compiled by CIclassinterfacestypespolymorphism

Summary#

An interface is a contract: what a type must provide, with no bodies and no state.

interface IBlobStore {
  string Put(string key, string body);
  string Name { get; }
}

class S3Store : IBlobStore {
  public string Put(string key, string body) { return "s3://" + key; }
  public string Name { get; } = "s3";
}

class GcsStore : IBlobStore {
  public string Put(string key, string body) { return "gs://" + key; }
  public string Name { get; } = "gcs";
}

A value typed as the interface accepts either, and the call runs whichever it holds:

string Upload(IBlobStore store, string key) {
  return store.Put(key, "…");        // "s3://k" or "gs://k" — decided by what `store` IS
}

Signature#

interface IName {
  ReturnType Method(params);         // an obligation to DO something
  Type Property { get; }             // an obligation to ANSWER something
  Type Property { get; set; }        // …and to accept one
}

class Name : Base, IOne, ITwo { … }  // one base class, then any number of contracts
interface IBoth : IOne, ITwo { }     // an interface may extend others

Members are public without saying so, and abstract without saying so — that is what an interface is.

Description#

Interface or abstract class?#

Both let you call through a shape rather than a concrete type. Choose by what you need to share:

interfaceabstract class
shared behaviour (a body)noyes
shared state (a field)noyes
how many a type may havemanyone

An interface is the right default for "these types all do X" — a store, a formatter, a notifier. Reach for an abstract class when implementors should share code, not just a shape.

Implementing one#

A type lists its contracts after its base, and must provide every member — the compiler names the ones it is missing. An inherited implementation counts:

class Logged : S3Store { }           // Put/Name come from S3Store, so `Logged` is an IBlobStore too

An abstract class may implement a contract partially and leave the rest to its subclasses.

Holding and testing one#

An interface is an ordinary type: a field, a parameter, a return, a collection element. is narrows back out of it:

string Describe(List<IBlobStore> stores) {
  var s = "";
  foreach (var store in stores) {
    s = s + store.Name;
    if (store is GcsStore) { s = s + "(google)"; }
  }
  return s;
}

What an interface may not do#

Each of these is refused with the reason, not a parse error:

  • It cannot be created. new IBlobStore() has no body to run — create one of the implementors.
  • It holds no state. A field is refused; a property contract (int Count { get; }) is how you require a value.
  • Its members take no body. Behaviour shared between implementors belongs on an abstract class.
  • An entity implements none. A row lives in one table told apart by one discriminator; a contract is a compile-time promise with nothing to store. Move the behaviour to a class.

A generic contract cannot be inherited yetclass R : IRepo<int> is refused, and so is class B : Box<int>. That is the generic-inheritance limit, not an interface one; the compiler says so where you write it.

Examples#

Choosing an implementation at run time — the shape this exists for:

string Store(bool useGcs, string key) {
  IBlobStore store = new S3Store();
  if (useGcs) { store = new GcsStore(); }
  return store.Name + " " + store.Put(key, "payload");
}

Two contracts on one type:

interface IAudited { string Who(); }

class AuditedS3 : S3Store, IAudited {
  public string Who() { return "auditor"; }
}

string Trace(IAudited a) { return a.Who(); }

See also#

Related

Class inheritance

A class can derive from another class with `class Circle : Shape`, inheriting its fields and its methods to any depth…

class methods

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

Classes

A class is an in-memory shape — data plus the behaviour that belongs to it — and it never touches the database. That is…

Sequence fields on a class

A class can hold many values in one field — `string[]`, `int[]`, `List<Tag>`, `HashSet<string>`, `Dictionary<string…