Delegation with by
by forwards a trait's required members to the one field of a single-field type, binding only to the trait or parenthesised group written directly in front of it.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
by forwards a trait to the one field of a type, so a wrapper around a single value does not have to write out
members that only ever call through to it.
Example#
type Seconds with Show, (Add, Subtract) by value, Compare by value {
value: Int
}
const total = Seconds(5) + Seconds(2)
print total
print total.max(Seconds(10))Syntax#
type <Name> with <Trait> by <field> { ... }
type <Name> with <Trait>, (<Trait>, <Trait>) by <field> { ... } `by` binds to the group right before itRules#
by <field>forwards the trait written directly in front of it to that field. In(Add, Subtract) by value,valueis the field that providesaddandsubtract.bybinds to one element of thewithlist - the trait or the parenthesised group directly before it - never to the whole list.Show, (Add, Subtract) by value, Compare by valuederivesShow, delegatesAddandSubtracttovaluein one group, and delegatesComparetovalueon its own; nothing aboutbyreaches back toShow. A group needs at least one trait and abyafter it -(Show)alone is the same as writingShow, and a group withoutbyis an error:Kompiliert nichttrait Loud { fn shout(): String } trait Quiet { fn whisper(): String } type Wrapper with (Loud, Quiet) { value: Int fn shout(): String { "loud" } fn whisper(): String { "quiet" } } // error: A group without `by` is an error: write the traits without parenthesesA
withlist separates its entries with commas only -&, which combines traits into one type everywhere a type is expected (Trait intersections), is not a separator here and is a parse error that names the fix:Kompiliert nichttype Wrapper with Add & Subtract by value { value: Int } // error: Traits delegated to the same field are grouped with parentheses, not `&`: write `(Add, Subtract) by value`Kompiliert nichttrait Loud { fn shout(): String } type Wrapper with Loud, Add by value { value: Int } // error: `Wrapper` implements `Loud` but has no `shout`byneeds a type with exactly one field, and the name afterbynames that field. A type with two fields has no single fieldAddcould mean, and a type with cases has no field of its own to name at all.byforwards the required members; the default members still come from the trait.total.max(Seconds(10))isCompare.max, a default that is written in terms ofcompare- the forwarded member - so it returns aSecondsand nothing has to be rewrapped by hand. A constant the trait requires is forwarded the same way:Seconds.zeroof astatic zero: Selfis the field type'sInt.zerowrapped into aSeconds, a constant of another type is the field type's value as it is, and a constant the trait gives a default is that default, read withSelfas the wrapper.A trait that is neither derived, delegated nor written by hand is not available on the wrapper.
Secondshas noMultiply, soSeconds(5) * Seconds(2)does not type check - which is the point, since multiplying two durations is not another duration.
What this is not#
by is not a way to expose the field. value still follows the usual field rules - private value: Int stays
unreadable from outside - by only wires the trait's members to it internally.
type Email with Show by value, TryFrom<String, String> {
private value: String
static fn tryFrom(text: String): Result<Email, String> {
if !text.contains("@") {
return Fail "'{text}' is not an email address"
}
Ok Self(text)
}
}
const email = Email.tryFrom "info@example.test"
print emailA field that is private is readable in the file that declares it and nowhere else, whatever by wires to it -
Path of std/path delegates nothing and hides its parts the same way:
use Path from "std/path"
const path = Path.from "a/b"
print path.componentValues
// error: `componentValues` is private to `Path`Related#
- Traits -
withat the declaration, and wherebysits inside a list of traits. - Coherence and blanket implementations - what still applies to a delegated implementation.