Literals

Oneway is values-only. There is no new, no implicit nullability, no keywords like true or false. Every value is built by calling its type's constructor.

Constructors

Every type T has a constructor T(_). The argument is a value matching the type's underlying definition:

KindConstructorArgument is…
PrimitiveInt(123), Float(1.0), String("hi")a literal of the corresponding lexical kind
HexHex(0xFF0000)a hex literal
Product A & BT(A(...) & B(...))a value-level product joined with &
Union A | BT(A(...)) or T(B(...))a value of any variant
NewtypeT(inner)a value of the aliased type

Literal Sugar

A handful of literals desugar to their constructors:

LiteralDesugars to
123Int(123)
1.0Float(1.0)
"abc"String("abc")
0xFF0000Hex(0xFF0000)

Numeric literals exist to avoid boilerplate in arithmetic-heavy code. String literals exist to avoid the parsing ambiguity of bare String(...) with spaces and punctuation.

Singleton Values

A singleton type — one with no underlying composition — has one value, referenced by writing the type name:

Noop      // the sole value of type Noop
On        // the sole value of type On

No Empty Constructors

String(), Int(), User() — calling any constructor with zero arguments is a compile-time error. If a value can legitimately be "missing", that absence belongs in the type as Option<T>. Otherwise the type requires its data.

For factory-style construction (an empty list, etc.), use an explicit method like List.empty or String.empty.

Constructing a Product

The argument to a product's constructor is its components joined with value-level &:

user = User(Birthday(...) & Username("ahanot"))
red  = Hex(0xFF0000)

& is overloaded across the two levels: at the type level it forms a product type, at the value level it forms a product value. The two never appear in the same context.

Validated Constructors (Type.Self)

By default, a type's constructor is total: T(inner) always succeeds and returns T. For types whose construction can fail — a Url parsed from a String, an Email from a String, etc. — the fallibility belongs in the type system as Result<T, E>. Same principle the language already applies to "missing": Option<T>.

A type opts into this by declaring a method named Self:

Url = String

extern Rust("oneway_url_parse")
Url.Self = (String) -> Result<Url, InvalidUrl>

Self is the alias for the receiver type's name; Type.Self reads as "the constructor that produces a Self."

When a type declares Type.Self, that is the constructor — the implicit total constructor is replaced. The signature is unconstrained: total ((String) -> Url), fallible (Result<Url, InvalidUrl>), or optional (Option<Url>). Call sites still use the ordinary constructor syntax Url("https://example.com"), but the expression's type is now whatever Url.Self returns, so a fallible constructor forces ? (or match) at the call site:

HttpClient.get(Url("https://example.com")?)?.print(Stdout)

External callers cannot bypass the constructor. The raw inner representation is only accessible inside the same file as the type.