Skip to main content

Classes

Mux provides object-oriented programming through classes and interfaces (traits).

Basic Class Definition​

basic_class.mux
Loading...

Key Points:

  • Fields must have explicit types (no auto inference)
  • Methods use self to access instance fields
  • Methods follow same rules as regular functions

Class Instantiation​

Classes use the .new() method pattern:

class_instantiation.mux
Loading...

Design Note: Mux uses explicit .new() rather than direct constructor calls to distinguish class instantiation from function calls and enum variant construction. The .new() method will always instantiate a new object with all default "zero" values for fields, and then you can set fields afterward. This is a simple and consistent pattern for object creation.

The Mux style for constructors is to use a common factory method (see below) that creates and initializes the object. Name factories by behavior (from(...), from_<source>(...), with_<feature>(...)) rather than new.

Interfaces (Traits)​

Interfaces define required methods that classes must implement:

interfaces.mux
Loading...

Implementing Interfaces​

Use the is keyword to implement interfaces:

implementing_interfaces.mux
Loading...

Note: Use is instead of implements (like Java). Multiple interfaces separated by commas.

Methods​

Instance Methods​

Access instance data via self:

instance_methods.mux
Loading...

Methods with Unused Parameters​

class_unused_params.mux
Loading...

Static Methods with common​

The common keyword declares static (class-level) methods:

static_methods.mux
Loading...

common vs const​

KeywordPurposeUsage
commonStatic methods and factory functionsClassName.method()
constImmutable constantsconst int MAX = 100

Key Differences:

  • Instance methods (no keyword) operate on self and require an instance
  • Static methods (common) have no self and are called on the class
  • Const fields are immutable instance/class fields, not methods
  • Static methods cannot access instance fields (no self context)

Constants in Classes​

Classes can have constant (immutable) fields:

class_constants.mux
Loading...

Const Enforcement:

  • Cannot reassign: self.MAX_RETRIES = value -> ERROR
  • Cannot increment/decrement: self.MAX_RETRIES++ -> ERROR
  • Use const for fields that shouldn't change after initialization

Generic Classes​

Classes can be generic over type parameters:

class_generics.mux
Loading...

See Generics for more details.

Built-in Capabilities​

Four capabilities are built into the language rather than declared. A class opts in by naming one and writing the method it requires, and the operators then work on that class:

CapabilityMethodWhat it enables
Equatableeq(Self) returns bool== and !=
Comparablecmp(Self) returns int<, <=, >, >=, and ==
Hashablehash() returns int and equse as a map key or set member
Stringableto_string() returns stringto_string() on the class

cmp returns negative, zero or positive like C's strcmp, so one method supplies every ordering operator. Comparable and Hashable each grant Equatable, so a class needs only the one that fits - and Hashable requires eq as well as hash, because a hash alone cannot tell two keys in one bucket apart.

class_capabilities.mux
Loading...

A class declaring Hashable can key a map, and instances match by their fields rather than by identity:

class_as_map_key.mux
Loading...

A generic class cannot declare Equatable, Comparable or Hashable: those are registered with the runtime once per class, and a generic class shares one registration across every instantiation. Stringable registers nothing and is available to generic classes.

Interface Dispatch​

Mux supports both static interface bounds and owned dynamic interface values. Use a type parameter when the concrete type is known at compile time. Use dyn<Interface> when a value must cross a function boundary without exposing its concrete class.

static_dispatch.mux
Loading...

An owned dynamic interface value stores the concrete object and its interface dispatch table. Passing a class to dyn<Interface> performs the checked conversion. Calling a method uses the table, so different classes can be handled by one function:

Mux
Loading...

Dynamic interface values own their erased object. They can be stored in heterogeneous collections through the dynamic interface type. Generic dynamic interfaces such as dyn<T> are not supported; name a declared interface.

Why static dispatch?

  • Zero cost: No pointer indirection, direct function calls
  • Inlining: LLVM can inline interface methods
  • Optimization: Better branch prediction, no indirect jumps

Static interface bounds still cannot be added to types from other modules. Use a named dynamic interface when a heterogeneous collection or erased function argument is required. Model a closed set of alternatives as an enum when dynamic dispatch is not needed.

Building a Class From a Document​

Document conversion is explicit Mux code. A class receives no generated serializer, deserializer, field rename, omit, flatten, or default mapping. Implement JsonRepresentable or CsvRepresentable when the class should provide the corresponding operation. Parser methods such as from_json and from_csv are ordinary user-written methods.

from_json.mux
Loading...

The name says what shape it returns:

MethodReturns
Config.to_json()result<Json, JsonError> - explicit class serialization
Config.from_json(text)result<Config, JsonError> - explicit class parsing
Config.list_from_json(text)result<list<Config>, JsonError> - only when explicitly defined
Config.to_csv()result<string, CsvError> - explicit class serialization
Config.from_csv(text)result<Config, CsvError> - only when explicitly defined

There is no compiler-provided singular or list parser. A CSV document is a table, but a program may define either shape when its input contract requires it.

A common parser contract​

The compiler does not impose these rules. They are a useful contract for an explicit parser that wants the same behavior as the standard shape fixtures:

CaseResult
A required field is missingerror naming the field
An optional<T> field is missingnone
An optional<T> field is nullnone
A field is the wrong kinderror naming the field and the type expected
The document has fields you did not declareignored

Absence and an explicit null deliberately mean the same thing. Extra fields are ignored so a server adding one does not break a program that reads it.

Shapes it understands​

nested_shapes.mux
Loading...

An error inside a nested class names the field that was actually wrong, not the one that contained it - missing required field 'qty', not "bad shipping".

Data whose shape you cannot declare​

JSON allows a heterogeneous array - [1, "two", true] is valid - and no Mux type holds those together. Declare such a field as Json and read each entry on its own terms:

escape_hatch.mux
Loading...

This is the escape hatch, and the reason Json accessors still exist: everything with a knowable shape goes through a class, and the rest goes through Json.

CSV is different​

A CSV cell is always text, so 3 in a file is the string "3". An int column is therefore parsed rather than type-checked, and an unparseable cell names the column:

column 'qty': expected an int

For the same reason a CSV column can only be a string, int, float, bool or an optional of those - a nested class cannot come out of a single cell. And optional there means the column may be absent from the header; within a row that has the column, an empty cell is an empty string, because CSV cannot tell "empty" from "absent" once the column exists.

Best Practices​

  1. Fields must be explicitly typed - No auto for class fields
  2. Use interfaces for polymorphism - Define common behavior
  3. Use common for factory methods - Create instances with pre-populated data
  4. Keep classes focused - Single responsibility principle
  5. Use const for immutable fields - Prevent accidental modification
  6. Use generic classes - Reusable data structures
  7. Prefer static dispatch - Better performance than dynamic dispatch

See Also​

  • Generics - Generic classes and type parameters
  • Interfaces - Built-in interfaces for common operations
  • Memory - Reference counting and object lifecycle
  • Functions - Method definitions