Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Class

constructor

class T { public T(params) { body } } → new T(args) { inits }

A class declares one constructor — its name is the class name, it takes no return type, and it runs when you write new T(args). The constructor body runs first; object initializers { Member = value } apply after it; new T(args) evaluates to the constructed object.

stable4 examples compiled by CIclassconstructionauthoring

Summary#

A constructor initializes a class instance. It is declared as a member whose name is the class name and which has no return type; you invoke it with new T(args). The constructor body runs first, then any object initializers { Member = value } are applied on top (so an initializer wins over a value the body set). new T(args) evaluates to the constructed object.

Signature#

class T {
  public T(<Type> p1, <Type> p2 = <default>) {   // no return type
    <statements>                                  // may read the params and assign this fields
  }

  public T() : this(<a>, <b>) { … }              // another one, chaining to the first
}

new T(a, b)                 // run the constructor these arguments select
new T(a, b) { Note = "x" }  // …then apply the initializer

Description#

  • A class may declare several constructors, told apart by their parameter TYPES exactly as methods are — new T(args) picks the one its arguments fit. Two that differ only in parameter NAMES are the same constructor declared twice, and a compile error. The name is the class name and there is no return type (a return; with a value is a compile error).
  • : this(…) chains to another constructor of the same class, which runs FIRST — so shared setup lives in one place. The chained-to constructor is the one that runs : base(…); a chaining constructor does not also run the base's, so a base constructor runs exactly once. A chain that comes back round to where it started is a compile error rather than unbounded recursion at construction time.
  • Visibility follows the class-member rule: public makes it callable from anywhere; a bare (unmarked) constructor is private — callable only from within its own class (the factory-method pattern).
  • new T(args) binds the arguments to the constructor's parameters (positional or name: value, with C# default-parameter values for omitted optionals), runs the body with the fresh instance in scope, and produces that instance.
  • Initializers run after the body: new T(args) { Member = value } runs the constructor first, then assigns each initializer — so an initializer overrides whatever the constructor set for that member (C# order). Initializer values cannot reference the object being constructed.
  • A class with no declared constructor uses the implicit default: new T() and new T { … } build the instance with no user code. Passing arguments to such a class is a compile error.
  • A field initializer runs before every constructor body (decimal Rate = 0.25m;), so the body reads the declared value and may overwrite it — C#'s order. Object initializers are the ones that run after.
  • A required parameter must be supplied: if the constructor has a non-optional parameter, new T { … } (no arguments) is a compile error — pass the argument.
  • Durable: a suspension inside a constructor body survives serialize/restore, and new T(args) still evaluates to the same constructed instance on resume.

Examples#

class Order {
  public int Qty;
  public decimal Total;
  public string Note;
  // The ctor assigns every required member, so `new Order(5, 2m)` compiles without also naming them in an
  // initializer — the compiler infers that the constructor satisfies them (no annotation needed).
  public Order(int qty, decimal price) {
    Qty = qty;
    Total = qty * price;
    Note = "new order";
  }
}

// The constructor sets the fields from its arguments.
decimal OrderTotal() {
  var o = new Order(5, 2m);
  return o.Total;                 // 10  (5 * 2, set in the body)
}

// An initializer is applied AFTER the body — so it wins.
string OrderNote() {
  var o = new Order(5, 2m) { Note = "rush" };
  return o.Note;                  // "rush"  (the body set "new order"; the initializer overrode it)
}
class Box {
  public int Size;
  public Box(int size = 3) { Size = size; }
}

int DefaultSize() { var b = new Box(); return b.Size; }   // 3  (the constructor's default)
int GivenSize()   { var b = new Box(7); return b.Size; }  // 7

// A class with no declared constructor keeps the plain build.
class Point { public int X; public int Y; }
int Origin() { var p = new Point { X = 0, Y = 0 }; return p.X + p.Y; }   // 0

Several constructors, and chaining between them#

Declare as many as differ in their parameter types. : this(…) runs another of them first, which is how shared setup stays in one place:

class Panel {
  public decimal Width;
  public decimal Height;

  public Panel(decimal width, decimal height) {   // the one that actually assigns
    Width = width;
    Height = height;
  }

  public Panel(decimal width) : this(width, 20m) { }   // chains to it
  public Panel() : this(10m) { }                       // …and so does this, one hop further
}

Each new picks by its arguments, and a chain runs all the way down before the chaining body:

[Test]
void Constructors_Select_And_Chain() {
  Assert.Equal(3m, new Panel(3m, 4m).Width);
  Assert.Equal(20m, new Panel(3m).Height);     // the default the one-arg constructor passed on
  Assert.Equal(10m, new Panel().Width);        // two hops: () → (decimal) → (decimal, decimal)
}

See also#

  • class methods — instance methods on a class (the same member-body mechanism the constructor reuses)
  • Typed locals — declaring the local that holds a constructed instance

Related

class methods

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

Typed locals

Locals can declare an explicit type instead of var; the declared type pins the binding. Literal initializers apply the…

Method overloads

A class can declare several methods with the same name, as long as they differ in their parameter types. Each call…