Scope and ownership
링크Use this page to declare protocol requirements, implement them, and add receiver methods.
This page owns protocol declarations, implementation conformance, protocol resolution, receiver self, and using.
Records, enums and newtypes owns nominal declarations and derives placement. Functions and generics owns ordinary function signatures, calls, and bound syntax. Standard library entries own the behavior of built-in methods.
Declaration forms
링크ProtocolDeclaration ="export"? "protocol" Identifier"{" ProtocolSignature* "}" ;ProtocolSignature ="function" Identifier FunctionTypeParameters?"(" FunctionParameters? ")" ("->" Type)? ;Implementation ="impl" FunctionTypeParameters? NamedType"{" ImplementationMethod* "}" ;ImplementationMethod ="export"? NamedFunction ;ProtocolReference = Identifier ("." Identifier)? ;UsingStatement ="using" Identifier "=" ControlOperand Block ;ConditionalDerivesClause ="derives" FunctionTypeParameters ProtocolReference "<" Type ">"("," ProtocolReference "<" Type ">")* ;
An export prefix publishes a module-level protocol declaration. Protocol references in bounds and conformance clauses use P or ns.P through the ordinary import boundary. One implementation head uses the ordinary named-type and type-argument grammar. Name resolution distinguishes a protocol application, which takes one conforming type, from a nominal receiver. Explicit binders precede either head. Protocol signatures use ordinary annotated parameters; their result annotation is required during checking. A conditional derives clause appears before the nominal body or newtype base.
Protocol bodies
A protocol body contains function signatures.
이유
A protocol states required operations independently of their implementations. Signatures give callers a contract without choosing the code that provides it.
Protocol implementation form
impl Protocol<Type> supplies definitions for one protocol and a complete conforming type. An explicit binder list precedes the protocol name for a conditional implementation. The protocol application has exactly one conforming type argument. Type aliases are expanded, and generic heads match the resolved static type through type equality, not value subtyping. A protocol call chooses the conformance before execution.
이유
Naming the resolved protocol and target type identifies one contract. Using the ordinary type grammar admits built-in, structural, and nominal targets without a new implementation notation.
Receiver implementation form
impl Type declares receiver methods for a nominal type owned by the current module. For a generic receiver, write explicit binders before its complete target, as in impl<T> Box<T>. Those binders enter method signatures and bodies; a method may introduce its own nested binders. The first bare self retains the instantiated receiver type even if a method binder shadows an outer name. The existing receiver name, field-collision, and export rules apply to every instantiation.
이유
Receiver methods already identify their type through the receiver expression. Explicit enclosing binders let generic receivers use the same method declarations and calls as concrete receivers.
Protocol method requirements
링크Protocol declarations use Self
A protocol declaration has no explicit type parameter list. Use Self for its conforming type. An explicit receiver binder is rejected during parsing with TPZ2001.
이유
An explicit receiver binder and Self both name the type that implements the protocol. The binder renames that role rather than introducing a different type relationship. Self preserves the same receiver intent and matches built-in protocol signatures.
The conforming type in signatures
Within a protocol method signature, Self denotes the conforming type.
이유
The conforming type must be substituted consistently throughout a protocol signature. This keeps its receiver and related arguments tied to the same implementation target.
Selecting the conforming type
A protocol method has an implicit conforming type parameter named Self. It may occur in any parameter or result type. Methods may have no value parameters. A call infers Self from its arguments and expected result through the ordinary generic-call rules. An explicit call type-argument list supplies Self first, followed by the method parameters. Dispatch requires one resolved conforming type; a call without enough inference evidence must supply that complete list.
이유
A constructor or decoder has no existing receiver value. Selecting the conforming type with the ordinary generic-call rules makes the same protocol operation usable before and after a value exists. No position in a value-parameter list owns dispatch.
Protocol return annotation
Every protocol method requires an explicit return annotation, including - for unit. An omitted annotation produces TPZ5022.
이유
A protocol signature has no body from which to infer a result. An explicit result type gives callers and implementations the same complete contract.
Ordinary function parameters in protocols
Protocol signatures use the type parameter, bound, annotated parameter, variadic, and default-expression rules of named functions. Method binders are distinct from implicit Self and are in scope throughout that method signature, including bounds and result types. They do not enter another method. Parameters remain immutable. Required fixed parameters precede the defaulted suffix; one final variadic parameter has no default and binds an array. The protocol declaration owns each default. Its names resolve in the protocol declaration environment, where value parameters are unavailable. Supplied arguments and omitted defaults follow ordinary call evaluation order.
The method type parameters follow implicit Self in the generic call signature. Implementation signature matching compares their resolved types and bounds after renaming corresponding binders. Protocol declarations have no body, so the result annotation remains required.
이유
A protocol promises callable operations. Giving those operations the same generic, variadic, and omission rules as named functions avoids a parallel helper-function interface. Keeping defaults in that promise gives every implementation and caller one omission behavior.
Unique protocol names
Redeclaring a user protocol name in the same module produces TPZ3008 during resolution.
이유
A protocol name must identify one contract in its module. Reusing the name would make conformance declarations ambiguous.
Unique protocol method names
Declaring the same method name twice in a protocol produces TPZ5008.
이유
A method name must identify one operation within a protocol. Duplicate names would make implementation coverage and calls ambiguous.
Built-in protocol names
Redeclaring the built-in protocols Eq, Order, Show, or JSON produces TPZ5008.
이유
Built-in operations and bounds use these protocol names. Redeclaring them could change the meaning of existing equality, ordering, display, or serialization code.
Protocol and type name collisions
Reusing a declared type name for a protocol in the same module produces TPZ3008 during resolution.
이유
Protocol and type names occur in implementation heads. Distinct names keep an implementation target from being mistaken for its protocol.
Module-level declarations
A protocol or implementation declaration inside a block produces TPZ5022.
이유
Conformance is checked for the program before execution. Module declarations keep the available implementation from depending on whether a block has executed.
Implementation conformance
링크Implementation ownership
The implementing module must define either the resolved protocol or the target type's outermost nominal declaration. A module may therefore define its own protocol for int, string, a structural type, or a generic type pattern. A foreign protocol requires an own-module record, enum, or newtype as the target's outermost constructor. A local type argument inside a foreign Array or Map does not transfer ownership. Transparent aliases preserve the underlying type and its owner. Implementing a foreign protocol for a foreign type produces TPZ5520. Every admitted implementation also passes the complete dependency graph's uniqueness check.
이유
The protocol owner can give an existing type a new operation without inventing a wrapper or a separate helper-function interface. The type owner can adopt an existing operation. Requiring one of those owners and rejecting graph-wide overlap gives each protocol and target pair one meaning.
Required implementation methods
An implementation supplies every declared protocol method and no undeclared method. A missing or undeclared method produces TPZ5022.
이유
Every operation promised by a protocol must be callable. Rejecting extra methods also catches a misspelled implementation name instead of leaving the intended operation missing.
Unique implementation methods
Implementing the same method twice in a protocol implementation produces TPZ5008.
이유
One implementation must supply one definition for each operation. Repeated definitions would make dispatch depend on declaration order.
Matching the protocol signature
Substitute the complete target for Self, keep implementation binders rigid, and pair method binders by position. Method binder counts, their sets of resolved protocol bounds, fixed parameter types, variadic position and element type, and result type must match. Type aliases and binder names do not create differences; bound order and parameter names do not affect a positional call. Repeated bounds still follow the ordinary duplicate-bound rule. The implementation may neither strengthen nor weaken a method's bound set. An explicit result annotation must equal the protocol result. When it is omitted, use the protocol result as the ordinary expected result while checking the body. Each return and tail must be assignable to that result; omission does not narrow the public signature. A signature mismatch produces TPZ5022.
이유
Callers have one complete signature before they see an implementation. Alpha-equivalence allows harmless renaming, while exact callable structure and bound identity preserve the same obligations. The protocol already supplies the result context, so repeating its annotation cannot be mandatory.
Implementation methods use ordinary functions
An implementation method is checked as an ordinary function against the protocol signature. Matching method generics and a matching variadic tail are admitted, and the result annotation may be omitted. Method-level export and parameter-default initializers produce TPZ5022. Conformance visibility already exposes the promised operations, and the protocol declaration already supplies omitted arguments. An implementation cannot create a second export or default contract, even by repeating the same default expression.
The implementation binder list encloses every method. Each method binder list is a nested lexical scope. A shadowed name denotes the inner binder; it is not silently identified with the outer binder during signature matching. Generic conformance defines the same scope for receiver implementations and conditional derives.
이유
Generic methods, variadic tails, and contextual results have the same function meaning inside an implementation. Visibility and defaults each already have one owner, so repeating either on a method would create competing descriptions of the same operation.
One conformance across the dependency graph
At most one conformance may apply to a resolved protocol and normalized target type throughout the complete resolved dependency graph. Expand aliases, retain defining-module nominal identities, and rename each declaration's binders before comparing target heads. Heads overlap when some consistent substitution makes their full target types equal. Repeated variables must keep the same substitution. Different positive bound sets cannot establish disjointness, even when no current type satisfies both. Reject every overlap with TPZ5521 before module initialization, whether it is manual/manual, manual/derive, or derive/derive. A concrete implementation has no priority over a generic one. Declaration order, import order, aliases, and method bodies cannot choose a winner. Distinct heads that cannot unify remain independent. Overlap diagnostics use the target of the later manual declaration in deterministic dependency-first module and source order. A conflict involving derive points to the derived protocol head; two derives use the later clause by the same order.
For example, Eq<Box<T>> overlaps Eq<Box<int>>. Mark<Box<int>> and Mark<Box<string>> are disjoint. Mark<Box<T>> and Mark<Box<U>> overlap even if their binders carry different positive bounds. Derive-generated conformances enter this same comparison. Normalization uses static type equality, so the rule does not add value-based or subtype-based implementation selection.
For two conflicting manual declarations, report the target of the later declaration in deterministic dependency-first module order, using source order within a module. If a derive clause participates, report its protocol head; for two derive clauses, choose the later clause by that same order. A secondary location may identify the other declaration. This reporting order never selects an implementation.
이유
Dispatch must identify one operation from its protocol and static type. Rejecting overlap makes that meaning independent of import and declaration order, and prevents later conformances from changing an earlier specialization choice. A stable primary location lets a caller fix the conflicting declaration without making import order affect which source is reported.
Generic binders and conditional conformance
An implementation places its type binders before its head, as in impl<T: Eq> Eq<Box<T>>. A receiver implementation uses the same placement, impl<T> Box<T>. Resolve the head to distinguish a protocol application from a nominal receiver; spelling, capitalization, and whitespace do not choose the meaning. Implementation binders scope over their bounds, the complete target type, and every method signature and body. Every implementation binder must occur in the target, so the selected target determines its arguments. Method binders have ordinary nested lexical scope and may shadow outer binders; matching uses resolved binder identities, never name strings. Each binder list has distinct names. A protocol method already has implicit Self in its binder scope. Bounds must have independent conformance evidence; an active obligation cannot prove itself. A generic nominal writes an explicit conditional derive binder list even when it has no bounds. Those binders scope only over that clause, correspond positionally to the nominal parameters, and may be renamed. Each derive target is the declaring nominal applied to all of those binders in declaration order. Fields and enum payloads keep the nominal declaration binders. Concrete and conditional manual and derived conformances use the same uniqueness rule.
Write record Box<T> derives<U: Eq> Eq<Box<U>> { value: T } to rename the clause-local binder. Its positional correspondence is with the nominal parameter T; it does not rebind T inside the fields. A concrete impl Eq<Box<int>> is a concrete head, while impl<T: Eq> Eq<Box<T>> covers every target satisfying the bound. They overlap and cannot coexist. A blanket implementation such as impl<T> Local<T> is permitted in the module defining Local and excludes every overlapping Local implementation. A type alias is expanded before ownership, matching, or overlap is decided.
이유
Explicit lexical binders make a generic conformance one reusable definition. Resolving types before comparing signatures prevents renaming or shadowing from capturing a different type variable. One conformance lookup for every instantiated target avoids overload or specialization priorities.
Implement equality for a generic wrapper
링크record Box<T> { value: T }impl<T: Eq> Eq<Box<T>> {function equals(a: Box<T>, b: Box<T>) -> bool {Eq.equals(a.value, b.value)}}let left: Box<int> = Box { value: 3 }let right: Box<int> = Box { value: 3 }let same: bool = Eq.equals(left, right)
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Protocol calls and resolution
링크Protocol-qualified calls
Resolve the protocol and method, then apply the ordinary generic-function call rules. The call type-parameter list is Self followed by the method binders in declaration order. Infer the complete list, or write it after the method name as Protocol.. Implementation binders are determined by the selected conforming type and are not extra call arguments. Parentheses around the callee preserve the same declaration signature. No separate Protocol<Type>. call form is introduced.
이유
A protocol-qualified operation is still one generic callable. One inference and explicit-specialization rule keeps ordinary functions, callbacks, and protocol calls compatible.
Protocol call conformance
Check conformance for the resolved Self type, independently of whether a value of that type occurs first, later, or only in the result. A generic body may use its declared protocol bound as conformance evidence. A concrete type without the required conformance produces TPZ5522. Dispatch uses that one conformance and does not select an implementation from the runtime value or from argument order.
이유
Arguments and results may establish the same conforming type. Looking up that type and the resolved protocol identity gives the operation one behavior without requiring a dummy receiver value.
Protocol argument forms
Protocol calls supply positional values and may spread an array into a declared variadic tail. Fixed omissions use the protocol defaults. The callee and supplied arguments are evaluated once from left to right; missing defaults follow in parameter order. Spread cannot fill an unsatisfied fixed slot. A named argument is rejected during parsing with TPZ2001, as in every other call.
이유
One argument-binding and evaluation rule lets an operation move between an ordinary function and a protocol without changing its call behavior.
Protocol bounds
A function protocol bound checks the inferred concrete type argument through conformance lookup. An unsatisfied bound produces TPZ5522.
이유
A generic body may use every operation promised by its bounds. Checking conformance when binding a concrete type keeps those operations available.
Conformance across modules
Manual and derived conformances are available in the defining module and in modules that import the nominal type. Import aliases preserve that conformance.
이유
A conformance belongs to the type and protocol identities. Importing that type must preserve its operations whether the methods are written or derived.
Conformance follows nominal origin across imports
Resolve a conformance by the protocol declaration identity and the normalized receiver type. User protocols and nominal types retain their defining module through selected or namespace imports and aliases. Same-spelled declarations in different modules remain distinct. Manual and derived conformances in the resolved dependency graph participate in the same coherence check. Import paths, aliases, and item order do not create or select another conformance. A manual call uses the implementation from the conformance-defining module. A receiver without an applicable conformance is rejected with TPZ5522. Conformance ownership and overlap follow the implementation rules.
이유
A call must keep its meaning when an import is renamed or moved. Resolve both the protocol and receiver type to their defining identities, and check one coherent set of conformances for the dependency graph. The defining module of a conformance determines its implementation, so aliases and import order cannot select a different body.
Protocol heads respect local values and declaration identity
A protocol declaration creates a non-value protocol binding in the same lexical and module name table as other declarations. It is private unless prefixed with export. Selected imports, selected aliases, and namespace imports resolve that binding by its defining module and declaration. Use P or ns.P in protocol bounds and conformance heads, and P.method or ns.P.method for calls. Aliases preserve identity; equal spellings in different modules remain different protocols. A same-scope name collision follows the module duplicate-binding rule. A nearer value or namespace owns an expression member access and is not reinterpreted as a protocol. Eq, Order, Show, and JSON remain predeclared protocol identities. Protocol names are not runtime values or nominal value types. A public callable may expose a user-protocol bound when that protocol is exported; a private bound is rejected with TPZ5524. Exported protocol method signatures obey the ordinary public-type visibility check. Importing a public type does not implicitly export the private protocols in its defining module. Derive eligibility is unchanged by importing a protocol name.
이유
Moving a generic API into a module must preserve its protocol contract. Protocols therefore use the ordinary explicit export and import boundary. One lexical binding table prevents a spelling from silently denoting separate declarations in the same scope. Defining identities survive aliases and keep independent modules from accidentally sharing conformances. Public signatures expose public contracts; private implementation details remain private.
A selected protocol alias preserves a public conformance
링크import std.io { writeLine }import contracts { Labelled as Described }import item { Item }function describe<T: Described>(value: T) -> string { Described.label(value) }writeLine(describe(Item { text: "selected" }))
selected
export protocol Labelled { function label(value: Self) -> string }
import contracts { Labelled }export record Item { text: string }impl Labelled<Item> {function label(value: Item) -> string { value.text }}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
selected
A namespace-qualified protocol resolves in bounds, impl heads, and calls
링크import std.io { writeLine }import contracts as apiimport item { Item }function describe<T: api.Labelled>(value: T) -> string { api.Labelled.label(value) }writeLine(describe(Item { text: "qualified" }))
qualified
export protocol Labelled { function label(value: Self) -> string }
import contracts as apiexport record Item { text: string }impl api.Labelled<Item> {function label(value: Item) -> string { value.text }}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
qualified
Equal protocol spellings in different modules keep different conformances
링크import std.io { writeLine }import first { Marked as First }import second { Marked as Second }import value { Item }function printBoth<T: First + Second>(value: T) -> () {writeLine(First.mark(value))writeLine(Second.mark(value))}printBoth(Item { text: "value" })
first value
second value
export record Item { text: string }
import value { Item }export protocol Marked { function mark(value: Self) -> string }impl Marked<Item> { function mark(value: Item) -> string { "first {value.text}" } }
import value { Item }export protocol Marked { function mark(value: Self) -> string }impl Marked<Item> { function mark(value: Item) -> string { "second {value.text}" } }
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
first valuesecond value
An exported function may expose an exported user protocol bound
링크export protocol Labelled { function label(value: Self) -> string }export function describe<T: Labelled>(value: T) -> string { Labelled.label(value) }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Reject a public callable that exposes a private protocol bound
링크protocol Hidden { function label(value: Self) -> string }export function describe<T: Hidden>(value: T) -> string { Hidden.label(value) }
표준 출력 없음.기대 결과
A private protocol is not selected through import
링크import contracts { Hidden }
표준 출력 없음.protocol Hidden { function label(value: Self) -> string }export let marker = 0
기대 결과
A protocol and a value cannot bind the same module-level name
링크protocol Labelled { function label(value: Self) -> string }let Labelled = 0
표준 출력 없음.기대 결과
An exported protocol cannot expose a private nominal parameter type
링크record Hidden { n: int }export protocol Render { function render(value: Self, input: Hidden) -> string }
표준 출력 없음.기대 결과
An exported protocol signature may use an exported nominal type
링크export record Input { n: int }export protocol Render { function render(value: Self, input: Input) -> string }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Namespace qualification whitespace cannot repeat one protocol bound
링크import contracts as apifunction describe<T: api.Labelled + api . Labelled>(value: T) -> string { api.Labelled.label(value) }
표준 출력 없음.export protocol Labelled { function label(value: Self) -> string }
기대 결과
Derived conformance
링크For declaration grammar, see Records, enums and newtypes.
Derivable protocols
For a nongeneric record, enum, or newtype, derives requests Eq, Order, Show, or JSON conformance. Another protocol name produces TPZ5530.
이유
Generated operations need a defined derivation for each field, variant payload, or newtype base. The built-in protocols supply those rules for all three nominal declaration forms.
Show derivation
Show derivation for a nongeneric record, enum, or newtype requires no member capability test. A newtype is displayed by its type name followed by its rendered base value in parentheses.
이유
Derived Show uses the shared value renderer, which handles every runtime value, including opaque values and functions. Its fields need no separate Show conformance.
Derivation field and payload requirements
Eq, Order, and JSON derivation check every record field, enum payload, or newtype base for equality, total ordering, or both JSON conversion operations. Each operation uses the capability domain described below. JSON decoding follows the declared normalization rules, including Option null conversion. A member that lacks the required capability produces TPZ5530.
이유
A generated operation visits the constituent fields or payloads. Each constituent must support the corresponding equality, ordering, or JSON conversion operation.
JSON conformance
JSON is an ordinary conformance with encode(value: Self) - and decode(value: JSON. An implementation supplies both methods. An empty marker produces the missing-method error TPZ5022. The ordinary protocol call rules infer Self or select it through the first explicit call type argument, as in JSON.. std. calls encode and then the canonical JSONValue writer. std. parses the text and calls the same decode implementation selected by JSON.. A codec returns an Err result for invalid input or a value it cannot encode. These failures do not become checker diagnostics. The manual decoder owns the accepted JSONValue shape. Derived record decoders ignore unknown object fields and use declared field defaults when a field is missing. A missing required field, wrong kind, unknown enum tag, or wrong payload arity returns an Err result. Malformed text fails before the decoder is called. JSON promises both conversion operations, with the representation and normalization defined for the type. Conversion may normalize distinct source values to the same decoded value. Existing Option conversion maps None() to null and Some(v) to the representation of v, so Some(None()) and Some(()) normalize to None() when decoded through an enclosing Option. Decode a JSONValue with JSON.. The receiver member tree. is removed and produces the ordinary missing-member diagnostic TPZ5006. Parsing text and writing text remain distinct operations through parseAs and stringify.
이유
A public codec should customize the same operation that library callers use. Supplying encode and decode through ordinary protocol methods lets a nominal type define its external representation without a second ad hoc serialization API. JSONValue separates typed conversion from parsing and canonical text output. The Result channel reports data failures in the same way for manual and derived implementations. Existing record default and Option normalization rules remain explicit conversion semantics. Decoding an existing tree has one public spelling, the ordinary protocol-qualified call. A receiver alias would repeat the same operation with identical input and output.
Built-in protocol signatures
The built-in method signatures are Show., Eq., Order., JSON., and JSON.. JSONValue is the parsed JSON tree type exported by std.json. JSON decode uses the ordinary protocol rule for selecting Self when there is no conforming input value.
이유
Shared signatures let user types participate in the same display, equality, and ordering operations. Callers do not need separate APIs for each type.
Nested and recursive derivation requirements
Deriving Eq, Order, or JSON composes the same operation on every record field, enum payload, or newtype base. A nested nominal uses its applicable manual or derived conformance after type arguments are substituted in its defining module. A manual method replaces structural inspection of that nominal; an outer derive must not bypass it or reject it because of private representation fields. A nested nominal with no required conformance produces TPZ5530. Built-in component families use the corresponding operation domain below.
Declared recursive and mutually recursive conformances may refer to one another. A recursive edge closes a declared conformance reference; it does not excuse a missing component capability elsewhere in the cycle. Establish each conditional instance using independent generic bound evidence before linking its recursive descriptors. An active generic bound cannot prove itself; a back-edge between already applicable declared derives is a descriptor reference, not evidence for that bound. A descriptor is identified by defining module, nominal declaration, and normalized type arguments. Keep references and captured substitutions and instantiate them as values are traversed, rather than eagerly expanding a schema tree. Imported aliases keep the same descriptor identity. Conditional generic instances follow the ordinary binder and coherence rules.
A derived JSON decoder follows the finite input tree. Each recursive aggregate step consumes a child JSON value; a descriptor loop that revisits the same input without structural progress returns Err. JSON starts at depth zero, permits depths through 128, and increments depth when descending to a record field, array element, map value, or enum payload. Descriptor references, Option wrapping, and newtype wrapping do not add a level. Data values follow value semantics. A depth above 128 returns an Err string beginning JSON_. The same traversal context covers nested derived dispatch. Descriptor expansion does not reset it. Manual method bodies retain ordinary function evaluation and resource behavior.
Derived equality and ordering use the same nested conformance as direct protocol calls. A declared nominal Eq or Order implementation also supplies the corresponding comparison operators, so moving a comparison inside a wrapper does not change its meaning. A structural comparison that exhausts its budget raises the existing TPZ5007 guard. Show retains its total debug rendering operation and does not introduce an Eq, Order, or JSON member requirement.
이유
A nominal conformance is the type author’s chosen operation, so composition calls it. Recursive declarations describe finite data trees under value semantics. Data values cannot contain cycles. Lazy descriptor references and bounded traversal support recursive declarations and deep values.
Field capability domains for derivation
Derivation follows the operation it generates. Eq asks whether two values are equal. Order supplies a total comparison. JSON supplies conversion to and from a JSON tree under the type's documented representation. These are different obligations, so admission is determined by the operation rather than a common whitelist. A nested nominal always uses the conformance described above. This table defines the listed component families; it does not assign capabilities to other built-ins. Duration capabilities follow its operations rule.
| Component | Eq | Order | JSON |
|---|---|---|---|
| int, string, bool | Value equality | Numeric, Unicode scalar, or false-before-true order | JSON number, string, or boolean |
| unit and null | Equality within the singleton type | Zero within the same singleton type | JSON null, recovered through the requested target type |
| float | IEEE numerical equality | No total Order because NaN has no place in the existing numerical relation | Finite numbers convert; NaN and infinities return Err |
| Array | Same length and elementwise equality | Lexicographic elements; a prefix precedes its extension | JSON array with recursive conversion |
| Option | Same constructor and payload equality | None() precedes Some(value). Compare present payloads | None() encodes as null. Some(value) unwraps its payload. Null payloads normalize on decoding |
| Result | Same constructor and payload equality | Err before Ok; compare payloads within the same constructor | The ordinary enum object with tag Ok or Err and one values entry |
| Map | Same lookup key identities and equal values, independent of insertion order | Requires an application-selected ordering | String keys form a JSON object; other key types need an explicit schema |
| Set | Same membership key identities, independent of insertion order | Requires an application-selected ordering | Requires an explicit sequence representation and duplicate policy |
| Structural record | Same field set and fieldwise equality | Compare fields in Unicode scalar order of field names | String field names form a JSON object |
| Union | Compare active member identities, then values within a member | Admitted when every member widens to the same ordered scalar domain | Untagged overlapping representations need an explicit nominal schema |
Map and Set equality reuse the key identity already used by lookup and membership. A custom Eq method does not replace stored-key equality. Map values use their Eq operation, including a manual nominal implementation. Insertion order does not affect either equality result. Functions and resources have no data-value equality, and regex denotation has no general equality operation. JSONValue and TOMLValue preserve representation information and require decoding or an explicit projection into the intended equality domain. Templates, ranges, mutable ByteBuffer values, and namespaces likewise have no automatic Eq conformance. Bytes compare bytes; Path and URL compare their canonical representations; Date, BigInt, and Decimal compare their values; Match and RoundingMode retain their declared value equality. IEEE equality is not an equivalence relation for NaN-containing values: NaN differs from itself and positive and negative zero compare equal. Eq does not promise otherwise.
For Order, Bytes compare bytewise; Path and URL compare canonical strings; Date compares calendar days; BigInt and Decimal compare numbers. A record uses sorted field names, including a nominal record, so rearranging declarations cannot change priority. A derived enum compares variant names in Unicode scalar order and then positional payloads. A newtype compares its base. Each component must itself have Order. Map and Set describe membership rather than a selected key order; a heterogeneous union has no declared cross-type priority. A nominal manual implementation can state those application-specific choices. Float keeps its ordinary IEEE relational predicates, which may all be false for NaN, and therefore does not satisfy total Order. Opaque families without a declared total order do not gain one through derivation.
JSON uses the existing record object, enum tag/values object, and transparent newtype representations. Result uses the enum representation rather than treating an Err payload as codec failure. Option converts through null and its payload values. Some(None()) and Some(()) can decode as None(). This normalization can map distinct source values to the same decoded value. JSONValue conversion preserves its tree, including stored number lexemes. Semantic scalar types such as Bytes, Path, URL, Date, BigInt, Decimal, Match, and RoundingMode need an explicitly chosen external schema through a nominal manual JSON implementation. Conversion does not silently pick a binary encoding, path base, unit, precision loss, or tag convention. Functions, resources, and templates cannot be reconstructed as data values. Derived conversion failure is TPZ5530 when a component type has no JSON capability. Malformed data and value-level encoding failures return an Err result during conversion.
Finite float encoding chooses the shortest decimal significand that recovers the identical binary64 value under nearest, ties-to-even decoding. If shortest candidates differ, choose the decimal closest to the exact binary value, then the candidate with an even final significand digit. Render fixed notation when the normalized decimal exponent is at least -6 and below 21; otherwise use lowercase e, with no plus sign or redundant exponent zeroes. Omit redundant fractional zeroes. Positive zero is 0 and negative zero is -0. A nonfinite input returns Err without substituting null or a string. Decoding accepts any JSON number, including integer lexemes, rounds once to binary64 with nearest, ties-to-even, preserves a negative zero sign, and rejects overflow to a nonfinite result. Underflow rounds to a finite subnormal or signed zero. The shortest-number rule applies when encoding a float; parsing and re-serializing an existing JSONValue preserves its accepted number lexeme, and numberText/asInt retain their existing semantics. Recursive conversion follows the depth rule above and value semantics. Show remains the total debug-render operation and has no member capability gate.
Duration has Eq and Order under its operations rule. Duration has no JSON capability in 6.0.
이유
Equal membership, lexicographic sequence order, total comparison, and JSON conversion answer different questions. Their requirements follow those questions. Map and Set equality should agree with lookup and membership instead of requiring an arbitrary insertion order. A total Order cannot inherit IEEE NaN comparison. A finite float can use the JSON number domain while the existing Result channel handles nonfinite values. JSON schemas that require an application choice stay explicit, and declaration layout does not choose a comparison priority.
Derived and manual conformance must be unique
이유
Generated implementations must participate in the same dispatch model as handwritten implementations.
Derive equality under an element bound
링크record Box<T> derives<T: Eq> Eq<Box<T>> { value: T }let left: Box<int> = Box { value: 3 }let right: Box<int> = Box { value: 3 }let same: bool = Eq.equals(left, right)
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Derive the existing protocols for a newtype
링크newtype Item derives Eq, Order, Show, JSON = intfunction jsonIdentity<T: JSON>(value: T) -> T { value }let value = Item(7)let same: bool = Eq.equals(value, value)let order: int = Order.compare(value, Item(8))let shown: string = Show.show(value)let retained: Item = jsonIdentity(value)
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Call derived Eq and Show on a newtype
링크import std.io { writeLine }newtype Item derives Eq, Show = intlet value = Item(7)writeLine("{Eq.equals(value, Item(7))}")writeLine("{Eq.equals(value, Item(8))}")writeLine(Show.show(value))
true
false
Item(7)
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
truefalseItem(7)
Use the conditional derive binder on a newtype
링크newtype Box<T> derives<T: Eq> Eq<Box<T>> = Tlet left: Box<int> = Box(3)let right: Box<int> = Box(3)let same: bool = Eq.equals(left, right)
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Require an explicit newtype conformance
링크newtype Item = intlet value = Item(7)let same = Eq.equals(value, value)
표준 출력 없음.기대 결과
A manual JSON implementation supplies both conversions
링크import std.json { JSONValue }record Token { text: string }impl JSON<Token> {function encode(value: Token) -> Result<JSONValue, string> {JSON.encode(value.text)}function decode(value: JSONValue) -> Result<Token, string> {match (value.asString()) {case Some(text) => Ok(Token { text: text })case None() => Err("expected token string")}}}
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Text and tree conversion use the same manual JSON implementation
링크import std.io { writeLine }import std.json { JSONValue, parse, parseAs, stringify }record Token { text: string }impl JSON<Token> {function encode(value: Token) -> Result<JSONValue, string> {JSON.encode(value.text)}function decode(value: JSONValue) -> Result<Token, string> {match (value.asString()) {case Some(text) => Ok(Token { text: text })case None() => Err("expected token string")}}}writeLine(match (stringify(Token { text: "paper" })) {case Ok(text) => textcase Err(message) => message})writeLine(match (parseAs<Token>("\"paper\"")) {case Ok(value) => value.textcase Err(message) => message})writeLine(match (parseAs<Token>("17")) {case Ok(value) => value.textcase Err(message) => message})writeLine(match (parse("\"ink\"")) {case Ok(tree) => match (JSON.decode<Token>(tree)) {case Ok(value) => value.textcase Err(message) => message}case Err(_) => "parse failed"})
"paper"
paper
expected token string
ink
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
"paper"paperexpected token stringink
An empty JSON marker omits the required conversion methods
링크record Token { text: string }impl JSON<Token> {}
표준 출력 없음.기대 결과
Derived JSON keeps record defaults and ignores unknown object fields
링크import std.io { writeLine }import std.json { parseAs, stringify }record Item derives JSON { name: string, count: int = 7 }let text = match (stringify({ name: "ink", extra: true })) {case Ok(value) => valuecase Err(message) => message}writeLine(match (parseAs<Item>(text)) {case Ok(value) => "{value.name}:{value.count}"case Err(message) => message})writeLine(match (parseAs<Item>("17")) {case Ok(_) => "unexpected value"case Err(_) => "wrong shape"})writeLine(match (parseAs<Item>("[")) {case Ok(_) => "unexpected value"case Err(_) => "malformed text"})
ink:7
wrong shape
malformed text
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
ink:7wrong shapemalformed text
JSONValue decoding uses the ordinary protocol call
링크import std.json { JSONValue }function read(tree: JSONValue) -> Result<int, string> {tree.decode<int>()}
표준 출력 없음.기대 결과
Decode a JSONValue with one protocol-qualified form
링크import std.json { JSONValue }function read(tree: JSONValue) -> Result<int, string> {JSON.decode<int>(tree)}
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Derived equality and operators use the inner manual equality
링크import std.io { writeLine }record Token { key: int, noise: int }impl Eq<Token> {function equals(a: Token, b: Token) -> bool { a.key == b.key }}record Box derives Eq { item: Token }let a = Box { item: Token { key: 1, noise: 10 } }let b = Box { item: Token { key: 1, noise: 20 } }let c = Box { item: Token { key: 2, noise: 10 } }writeLine("{Eq.equals(a, b)}")writeLine("{a == b}")writeLine("{Eq.equals(a, c)}")writeLine("{a != c}")
true
true
false
true
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
truetruefalsetrue
A manual equality hides an opaque field from outer operators
링크import std.io { writeLine }record Callback { key: int, run: () -> int }impl Eq<Callback> {function equals(a: Callback, b: Callback) -> bool { a.key == b.key }}record Box derives Eq { item: Callback }let a = Box { item: Callback { key: 1, run: () => 7 } }let b = Box { item: Callback { key: 1, run: () => 9 } }writeLine("{a == b}")writeLine("{Eq.equals(a, b)}")
true
true
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
truetrue
Derived ordering and operators use the inner manual ordering
링크import std.io { writeLine }record Rank { score: int }impl Order<Rank> {function compare(a: Rank, b: Rank) -> int {if (a.score > b.score) { -1 } else if (a.score < b.score) { 1 } else { 0 }}}record Box derives Order { item: Rank }let a = Box { item: Rank { score: 9 } }let b = Box { item: Rank { score: 3 } }writeLine("{Order.compare(a, b)}")writeLine("{a < b}")writeLine("{Order.compare(b, a)}")writeLine("{b > a}")
-1
true
1
true
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
-1true1true
Derived JSON uses the nested manual codec in both directions
링크import std.io { writeLine }import std.json { JSONValue, parseAs, stringify }record Token { text: string }impl JSON<Token> {function encode(value: Token) -> Result<JSONValue, string> {JSON.encode(value.text)}function decode(value: JSONValue) -> Result<Token, string> {match (value.asString()) {case Some(text) => Ok(Token { text: text })case None() => Err("expected token string")}}}record Envelope derives JSON { token: Token }let text = match (stringify(Envelope { token: Token { text: "paper" } })) {case Ok(value) => valuecase Err(message) => message}writeLine(text)writeLine(match (parseAs<Envelope>(text)) {case Ok(value) => value.token.textcase Err(message) => message})
{"token":"paper"}
paper
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
{"token":"paper"}paper
A finite recursive enum value encodes and decodes
링크import std.io { writeLine }import std.json { parseAs, stringify }enum Chain derives Eq, JSON { End, Next(int, Chain) }let original = Chain.Next(7, Chain.End())let text = match (stringify(original)) {case Ok(value) => valuecase Err(message) => message}writeLine(text)writeLine(match (parseAs<Chain>(text)) {case Ok(value) => "{Eq.equals(value, original)}"case Err(message) => message})
{"tag":"Next","values":[7,{"tag":"End"}]}
true
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
{"tag":"Next","values":[7,{"tag":"End"}]}true
Mutually recursive declarations share conformance references
링크record Folder derives Eq, JSON { entries: Array<Entry> }enum Entry derives Eq, JSON { File(string), Directory(Folder) }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Inserted values keep recursive JSON finite
링크import std.io { writeLine }import std.json { stringify }record Node derives JSON { children: Array<Node> }let mut children: Array<Node> = []let root = Node { children: children }children.push(root)writeLine("{root.children.length}:{children.length}")writeLine(match (stringify(root)) {case Ok(value) => "Ok {value}"case Err(_) => "unexpected error"})
0:1
Ok {"children":[]}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
0:1Ok {"children":[]}
The record retains its empty children value after children.. Insertion follows value semantics and cannot create a cycle.
Inserted values keep recursive comparison finite
링크import std.io { writeLine }record Node derives Eq { children: Array<Node> }let mut children: Array<Node> = []let root = Node { children: children }let peer = Node { children: children }children.push(root)writeLine("{Eq.equals(root, peer)}:{root.children.length}:{children.length}")
true:0:1
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
true:0:1
The record retains its empty children value after children.. Insertion follows value semantics and cannot create a cycle.
Outer derivation does not invent an inner nominal conformance
링크record Inner { value: int }record Outer derives Eq { item: Inner }
표준 출력 없음.기대 결과
Nested dispatch preserves the imported nominal identity
링크import std.io { writeLine }import tokens { Token as Ink }record Box derives Eq { value: Ink }let a = Box { value: Ink { key: 4, label: "first" } }let b = Box { value: Ink { key: 4, label: "second" } }writeLine("{Eq.equals(a, b)}")
true
export record Token { key: int, label: string }impl Eq<Token> {function equals(a: Token, b: Token) -> bool { a.key == b.key }}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
true
Map and Set equality follows membership while Map values use Eq
링크import std.io { writeLine }record Token { key: int, label: string }impl Eq<Token> {function equals(a: Token, b: Token) -> bool { a.key == b.key }}record Index derives Eq { values: Map<string, Token>, keys: Set<int> }let a = Index {values: map { "a": Token { key: 1, label: "first" }, "b": Token { key: 2, label: "second" } },keys: set { 1, 2 },}let b = Index {values: map { "b": Token { key: 2, label: "changed" }, "a": Token { key: 1, label: "changed" } },keys: set { 2, 1 },}let c = Index {values: map { "a": Token { key: 9, label: "first" }, "b": Token { key: 2, label: "second" } },keys: set { 1, 2 },}writeLine("{Eq.equals(a, b)}")writeLine("{a == b}")writeLine("{Eq.equals(a, c)}")
true
true
false
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
truetruefalse
Boolean, singleton, sequence, sum, and structural record orders compose
링크import std.io { writeLine }record Flag derives Order { value: bool }record UnitBox derives Order { value: () }record NullBox derives Order { value: null }record Sequence derives Order { value: Array<int> }record Optional derives Order { value: Option<int> }record Outcome derives Order { value: Result<int, int> }record Fields derives Order { value: { z: int, a: int } }writeLine("{Order.compare(Flag { value: false }, Flag { value: true })}")writeLine("{Order.compare(UnitBox { value: () }, UnitBox { value: () })}")writeLine("{Order.compare(NullBox { value: null }, NullBox { value: null })}")writeLine("{Order.compare(Sequence { value: [1, 2] }, Sequence { value: [1, 3] })}")writeLine("{Order.compare(Sequence { value: [1] }, Sequence { value: [1, 0] })}")writeLine("{Order.compare(Optional { value: None() }, Optional { value: Some(0) })}")writeLine("{Order.compare(Outcome { value: Err(7) }, Outcome { value: Ok(0) })}")writeLine("{Order.compare(Fields { value: { z: 0, a: 2 } }, Fields { value: { z: 100, a: 1 } })}")
-1
0
0
-1
-1
-1
-1
1
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
-100-1-1-1-11
Reordering record fields or enum declarations does not change derived order
링크import std.io { writeLine }record First derives Order { z: int, a: int }record Second derives Order { a: int, z: int }enum Forward derives Order { Zed, Alpha }enum Reordered derives Order { Alpha, Zed }writeLine("{Order.compare(First { z: 0, a: 2 }, First { z: 100, a: 1 })}")writeLine("{Order.compare(Second { z: 0, a: 2 }, Second { z: 100, a: 1 })}")writeLine("{Order.compare(Forward.Alpha(), Forward.Zed())}")writeLine("{Order.compare(Reordered.Alpha(), Reordered.Zed())}")
1
1
-1
-1
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
11-1-1
A union within one ordered scalar domain keeps that order
링크import std.io { writeLine }record Choice derives Order { value: 1 | 2 }writeLine("{Order.compare(Choice { value: 1 }, Choice { value: 2 })}")
-1
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
-1
Map membership has no implicit total ordering
링크record Lookup derives Order { values: Map<string, int> }
표준 출력 없음.기대 결과
Set membership has no implicit total ordering
링크record Membership derives Order { values: Set<int> }
표준 출력 없음.기대 결과
Different ordered scalar domains do not acquire a cross-type order
링크record Mixed derives Order { value: int | string }
표준 출력 없음.기대 결과
JSON object keys require strings without an implicit key conversion
링크record NumericKeys derives JSON { values: Map<int, string> }
표준 출력 없음.기대 결과
A Set needs an explicitly chosen JSON representation
링크record Membership derives JSON { values: Set<int> }
표준 출력 없음.기대 결과
Eq uses IEEE float equality and does not claim NaN reflexivity
링크import std.io { writeLine }record Reading derives Eq { value: float }let sample = Reading { value: 0.0 / 0.0 }writeLine("{Eq.equals(sample, sample)}")writeLine("{sample == sample}")
false
false
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
falsefalse
Finite floats have one JSON number conversion and preserve negative zero
링크import std.io { writeLine }import std.json { parseAs, stringify }record Reading derives JSON { value: float }writeLine(match (stringify(Reading { value: 1.5 })) {case Ok(text) => textcase Err(message) => message})writeLine(match (stringify(-0.0)) {case Ok(text) => textcase Err(message) => message})writeLine(match (stringify(1000.0)) {case Ok(text) => textcase Err(message) => message})writeLine(match (parseAs<float>("-0")) {case Ok(value) => "{(1.0 / value) < 0.0}"case Err(message) => message})writeLine(match (parseAs<float>("1")) {case Ok(value) => "{value == 1.0}"case Err(message) => message})writeLine(match (stringify(0.0 / 0.0)) {case Ok(_) => "unexpected value"case Err(_) => "nonfinite rejected"})writeLine(match (parseAs<float>("1e9999")) {case Ok(_) => "unexpected value"case Err(_) => "overflow rejected"})
{"value":1.5}
-0
1000
true
true
nonfinite rejected
overflow rejected
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
{"value":1.5}-01000truetruenonfinite rejectedoverflow rejected
Option JSON conversion explicitly normalizes null payloads
링크import std.io { writeLine }import std.json { parseAs, stringify }let original: Option<Option<int>> = Some(None())writeLine(match (stringify(original)) {case Ok(text) => textcase Err(message) => message})writeLine(match (parseAs<Option<Option<int>>>("null")) {case Ok(value) => match (value) {case None() => "none"case Some(_) => "some"}case Err(message) => message})
null
none
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
nullnone
Result data uses the same tagged representation as enum data
링크import std.io { writeLine }import std.json { parseAs, stringify }record Outcome derives JSON { value: Result<int, string> }let value = Outcome { value: Err("paper") }let text = match (stringify(value)) {case Ok(encoded) => encodedcase Err(message) => message}writeLine(text)writeLine(match (parseAs<Outcome>(text)) {case Ok(decoded) => match (decoded.value) {case Ok(number) => "{number}"case Err(message) => message}case Err(message) => message})
{"value":{"tag":"Err","values":["paper"]}}
paper
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
{"value":{"tag":"Err","values":["paper"]}}paper
Receiver methods and self
링크Receiver self parameter
A receiver method starts with bare self, with no annotation, default, or variadic marker. Its type is the implementation target, and a missing or differently written receiver produces TPZ5022.
이유
The implementation target already determines the receiver type. A bare self avoids repeating that type in every method and gives receiver binding one form.
Unique receiver method names
Repeating a receiver method name for the same type produces TPZ5008.
이유
Member lookup needs one method for a given type and name. Duplicate definitions would make a call depend on declaration order.
Receiver member collisions
A receiver method name that collides with a record field or reserved built-in member produces TPZ5022.
이유
Fields, built-in members, and receiver methods share member access syntax. Distinct names prevent the same access from denoting different operations.
Exporting receiver methods
export may precede an individual receiver method declaration.
이유
Exporting individual methods lets a type expose useful operations while keeping helpers private. It uses the same declaration prefix as other module exports.
Using a resource
링크Scope cleanup runs on normal completion and structured exits. The File resource contract defines repeated close and host close failures. Ordinary runtime faults follow the fault cleanup rule.
File resource bindings
using name = (expression) { . checks the resource expression against File and gives its block binding type File.
이유
The cleanup path invokes the File close operation. Requiring a File ensures that this operation is defined for the acquired resource.
Immutable resource bindings
A using resource binding is immutable.
이유
Cleanup is registered for the acquired resource. Preventing reassignment keeps the visible binding tied to the resource that will be closed.
Using acquisition and cleanup order
A using initializer is evaluated once. After successful acquisition, its automatic close is registered before the body. An initializer that propagates an Err registers no close for that resource. Body defers run before its close under the scope cleanup rule, including ? propagation. Capturing the File does not keep it open beyond the using scope. Ordinary runtime faults follow the fault cleanup rule.
Ordinary runtime faults follow the fault cleanup rule.
A deadline discards remaining using cleanup under abandoned arm cleanup. The runtime reclaims the abandoned arm's host resource handles when the group finishes.
이유
Body defers may still need the resource. Running them before close and leaving nested scopes from inside to outside keeps those dependencies alive.
Explicit close and failure boundaries
using keeps automatic File. registered after an explicit close.
File. follows the File resource contract. That contract defines repeated close, shared closed state and close faults.
The scope cleanup rule defines cleanup order, structured exits and retained body values. Ordinary runtime faults follow the fault cleanup rule.
Deferred runtime and host errors follow the run exit contract and test result contract. These contracts determine process failure and test output independently of the stored body value.
Deadline abandonment follows abandoned arm cleanup. It skips remaining using cleanup while the runtime reclaims the arm's host handles when the group finishes.
At the cited native-host source revision, close sets the shared closed flag. Repeating that assignment preserves the closed state. Later reads and writes report a closed file. The File resource contract defines the required behavior across hosts.
A deadline discards remaining using cleanup under abandoned arm cleanup. The runtime reclaims the abandoned arm's host resource handles when the group finishes.
이유
Cleanup registration belongs to the scope, so an explicit close does not cancel it. The File resource contract owns the result of closing. Command contracts own exit status and test output.
Complete examples
링크Implement and call a protocol
링크protocol Labelled {function label(value: Self) -> string}record Item { name: string }impl Labelled<Item> {function label(value: Item) -> string { value.name }}let text: string = Labelled.label(Item { name: "Moss" })
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Reject an explicit protocol receiver binder
링크protocol Labelled<T> {function label(value: T) -> string}record Item { name: string }impl Labelled<Item> {function label(value: Item) -> string { value.name }}let text: string = Labelled.label(Item { name: "Moss" })
표준 출력 없음.기대 결과
Use Self for the conforming type
링크protocol Labelled {function label(value: Self) -> string}record Item { name: string }impl Labelled<Item> {function label(value: Item) -> string { value.name }}let text: string = Labelled.label(Item { name: "Moss" })
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Declare a receiver method
링크record Item { name: string }impl Item {function label(self) -> string { self.name }}let item = Item { name: "Moss" }let text: string = item.label()
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Derive built-in protocols
링크record Pair derives Eq, Order, Show, JSON {left: int,right: int,}let pair = Pair { left: 1, right: 2 }let same: bool = Eq.equals(pair, pair)
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Check a File resource binding
링크function manage(file: File) -> () {using resource = (file) {let handle: File = resource}}
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Reject an incomplete implementation
링크protocol Labelled {function label(value: Self) -> string}record Item { name: string }impl Labelled<Item> {}
표준 출력 없음.error[TPZ5022]: `impl Labelled<Item>` is missing method `label`
--> example.tpz:7:6
|
7 | impl Labelled<Item> {}
| ^^^^^^^^
example.tpz: 1 type diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5022]: `impl Labelled<Item>` is missing method `label`--> example.tpz:7:6|7 | impl Labelled<Item> {}| ^^^^^^^^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5022; cause missing-protocol-method; primary location asserted; additional diagnostics allow
A foreign protocol on a foreign type violates ownership
링크impl Show<int> {function show(value: int) -> string { "number" }}
표준 출력 없음.기대 결과
The preserved receipt belongs to an earlier revision that rejected a local protocol on int. This revision checks the orphan case where both Show and int belong to another module. The 6.0 contract permits the local-protocol case shown separately.
Reject a repeated conformance
링크protocol Labelled {function label(value: Self) -> string}record Item { name: string }impl Labelled<Item> {function label(value: Item) -> string { value.name }}impl Labelled<Item> {function label(value: Item) -> string { value.name }}
표준 출력 없음.error[TPZ5521]: `Item` already conforms to `Labelled` by a previous `impl`; a conformance must be unique
--> example.tpz:11:15
|
11 | impl Labelled<Item> {
| ^^^^
example.tpz: 1 type diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5521]: `Item` already conforms to `Labelled` by a previous `impl`; a conformance must be unique--> example.tpz:11:15|11 | impl Labelled<Item> {| ^^^^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5521; cause duplicate-protocol-conformance; primary location asserted; additional diagnostics allow
Reject a call without conformance
링크protocol Labelled {function label(value: Self) -> string}record Item { name: string }let text: string = Labelled.label(Item { name: "Moss" })
표준 출력 없음.error[TPZ5522]: `Item` does not conform to `Labelled`
--> example.tpz:7:35
|
7 | let text: string = Labelled.label(Item { name: "Moss" })
| ^^^^^^^^^^^^^^^^^^^^^
example.tpz: 1 type diagnostic
기대 결과
기대 결과
거절 단계 check. 종료 코드가 0이 아닙니다.
protocol-call-argument-does-not-conform at
example.tpz:7:35
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5522]: `Item` does not conform to `Labelled`--> example.tpz:7:35|7 | let text: string = Labelled.label(Item { name: "Moss" })| ^^^^^^^^^^^^^^^^^^^^^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5522; cause protocol-call-argument-does-not-conform; primary location asserted; additional diagnostics allow
Reject a user-defined protocol in derives
링크protocol Labelled {function label(value: Self) -> string}record Item derives Labelled { name: string }
표준 출력 없음.error[TPZ5530]: unknown protocol `Labelled` in `derives` for `Item`; derivable protocols are `Eq`, `Order`, `Show`, `JSON`
--> example.tpz:5:21
|
5 | record Item derives Labelled { name: string }
| ^^^^^^^^
example.tpz: 1 type diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5530]: unknown protocol `Labelled` in `derives` for `Item`; derivable protocols are `Eq`, `Order`, `Show`, `JSON`--> example.tpz:5:21|5 | record Item derives Labelled { name: string }| ^^^^^^^^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5530; cause protocol-is-not-derivable; primary location asserted; additional diagnostics allow
Acquire once, run body defers, then close
링크import std.iolet mut acquisitions = 0let mut later: () -> string = () => "unset"function acquire() -> Result<File, string> {acquisitions += 1io.open("input.txt")}function scenario() -> Result<int, string> {using file = (acquire()?) {later = () => match (file.read()) {case Ok(text) => textcase Err(e) => e}defer { io.writeLine(match (file.read()) {case Ok(text) => "defer:{text}"case Err(e) => "defer:{e}"}) }io.writeLine("body")99}Ok(7)}let ignored = scenario()io.writeLine("acquisitions:{acquisitions}")io.writeLine(later())
body
defer:payload
acquisitions:1
file is closed
payload
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
bodydefer:payloadacquisitions:1file is closed
Close on return, propagation, break, and continue
링크import std.iolet mut later: () -> string = () => "unset"function fail() -> Result<int, string> { Err("stop") }function onReturn() -> Result<int, string> {using file = (io.open("input.txt")?) {later = () => match (file.read()) {case Ok(text) => textcase Err(e) => e}return Ok(7)}Ok(0)}let ignoredonReturn = onReturn()io.writeLine("onReturn:{later()}")function onQuestion() -> Result<int, string> {using file = (io.open("input.txt")?) {later = () => match (file.read()) {case Ok(text) => textcase Err(e) => e}fail()?}Ok(0)}let ignoredonQuestion = onQuestion()io.writeLine("onQuestion:{later()}")function onBreak() -> Result<int, string> {let mut i = 0while (i < 1) {using file = (io.open("input.txt")?) {later = () => match (file.read()) {case Ok(text) => textcase Err(e) => e}break}}Ok(0)}let ignoredonBreak = onBreak()io.writeLine("onBreak:{later()}")function onContinue() -> Result<int, string> {let mut i = 0while (i < 1) {using file = (io.open("input.txt")?) {later = () => match (file.read()) {case Ok(text) => textcase Err(e) => e}i += 1continue}}Ok(0)}let ignoredonContinue = onContinue()io.writeLine("onContinue:{later()}")
onReturn:file is closed
onQuestion:file is closed
onBreak:file is closed
onContinue:file is closed
payload
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
onReturn:file is closedonQuestion:file is closedonBreak:file is closedonContinue:file is closed
Explicit and automatic close on the installed native host
링크import std.iolet mut later: () -> string = () => "unset"function scenario() -> Result<int, string> {using file = (io.open("input.txt")?) {later = () => match (file.read()) {case Ok(text) => textcase Err(e) => e}file.close()file.close()io.writeLine(later())}Ok(0)}let ignored = scenario()io.writeLine(later())
file is closed
file is closed
payload
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
file is closedfile is closed
This example tests repeated close on the installed native host. The File resource contract requires the same close result across hosts.
Reject a non-File resource initializer
링크using resource = (1) {}
표준 출력 없음.기대 결과
Use a File resource initializer
링크function manage(file: File) -> () {using resource = (file) {}}
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Check nested concrete members and recursive Eq or Order
링크record Leaf derives Eq, Order, JSON { value: int }record Box derives Eq, Order, JSON { value: Leaf }record Nested derives Eq, Order, Show, JSON { value: Box }enum Tree derives Eq, Show { Leaf(int), Branch(Array<Tree>) }enum Chain derives Eq, Order { End, Next(int, Chain) }record Callable derives Show { run: () -> int }record Document derives Eq, JSON { items: Array<Option<Leaf>> }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Map value equality satisfies Eq derivation
링크record Index derives Eq { values: Map<string, int> }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Use comparable array elements
링크record Comparable derives Eq { values: Array<int> }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Reject a float field when deriving total Order
링크record NonTotal derives Order { value: float }
표준 출력 없음.기대 결과
Use a totally orderable field
링크record Total derives Order { value: int }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
A recursive declaration has a reusable JSON conformance
링크enum Recursive derives JSON { End, Next(Recursive) }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Use finite JSON payloads
링크enum Finite derives JSON { End, Value(int) }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
A nested manual Eq implementation satisfies outer derivation
링크record Callback { run: () -> int }impl Eq<Callback> {function equals(a: Callback, b: Callback) -> bool { true }}record Outer derives Eq { item: Callback }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Show does not require nested comparability
링크record Callback { run: () -> int }impl Eq<Callback> {function equals(a: Callback, b: Callback) -> bool { true }}record Outer derives Show { item: Callback }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Reject duplicate manual and derived Eq
링크record Item derives Eq { value: int }impl Eq<Item> {function equals(a: Item, b: Item) -> bool { a.value == b.value }}
표준 출력 없음.기대 결과
Keep one conformance per protocol
링크record Item derives Show { value: int }impl Eq<Item> {function equals(a: Item, b: Item) -> bool { a.value == b.value }}
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Null supports Eq and JSON derivation
링크record Nil derives Eq, JSON { value: null }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
An imported nominal alias keeps its derived conformance
링크import remote { Item as RemoteItem }record Item { n: int }let imported = RemoteItem { n: 1 }let same: bool = Eq.equals(imported, imported)
example.tpz: types-ok (2 modules)
example.tpz: resolve-ok (2 modules)
export record Item derives Eq { n: int }
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (2 modules)example.tpz: resolve-ok (2 modules)
A local type does not inherit the imported namesake conformance
링크import remote { Item as RemoteItem }record Item { n: int }let localValue = Item { n: 1 }let same = Eq.equals(localValue, localValue)
표준 출력 없음.export record Item derives Eq { n: int }
기대 결과
Give the local type its own conformance
링크import remote { Item as RemoteItem }record Item derives Eq { n: int }let localValue = Item { n: 1 }let same = Eq.equals(localValue, localValue)
example.tpz: types-ok (2 modules)
example.tpz: resolve-ok (2 modules)
export record Item derives Eq { n: int }
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (2 modules)example.tpz: resolve-ok (2 modules)
A manual conformance is visible through a nominal import
링크import remote { Item as RemoteItem }let imported = RemoteItem { n: 1 }let same = Eq.equals(imported, imported)
표준 출력 없음.export record Item { n: int }impl Eq<Item> {function equals(a: Item, b: Item) -> bool { a.n == b.n }}
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
A derived conformance is visible through a nominal import
링크import remote { Item as RemoteItem }let imported = RemoteItem { n: 1 }let same = Eq.equals(imported, imported)
표준 출력 없음.export record Item derives Eq { n: int }
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
A local value owns the member call despite a protocol namesake
링크import std.ioprotocol Labelled { function label(value: Self) -> string }record Item { name: string }impl Labelled<Item> {function label(value: Item) -> string { value.name }}function localLabel() -> string {let Labelled = { label: (value: Item) => "local" }Labelled.label(Item { name: "protocol" })}io.writeLine(localLabel())
local
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
local
Reject a user protocol with a built-in protocol name
링크protocol Eq { function custom(value: Self) -> int }
표준 출력 없음.기대 결과
기대 결과
거절 단계 check. 종료 코드가 0이 아닙니다.
structures-builtin-protocol-redeclaration at
example.tpz:1:10
Choose a distinct user protocol name
링크protocol Custom { function custom(value: Self) -> int }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Evaluate the return value, then close nested resources
링크import std.iolet mut outerClosed: () -> bool = () => falselet mut innerClosed: () -> bool = () => falsefunction isClosed(file: File) -> bool {match (file.read()) {case Ok(text) => falsecase Err(error) => true}}function makeResult() -> Result<int, string> {io.writeLine("return-value")Ok(7)}function scenario() -> Result<int, string> {using outer = (io.open("input.txt")?) {outerClosed = () => isClosed(outer)defer { io.writeLine("outer-defer:inner-closed={innerClosed()}") }using inner = (io.open("input.txt")?) {innerClosed = () => isClosed(inner)defer { io.writeLine("inner-defer") }return makeResult()}}Ok(0)}let outcome = scenario()io.writeLine(match (outcome) {case Ok(value) => "result:{value}"case Err(error) => "open:{error}"})io.writeLine("outer-closed:{outerClosed()}")io.writeLine("inner-closed:{innerClosed()}")
return-value
inner-defer
outer-defer:inner-closed=true
result:7
outer-closed:true
inner-closed:true
payload
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
return-valueinner-deferouter-defer:inner-closed=trueresult:7outer-closed:trueinner-closed:true
The native File read result makes closing observable. The outer body defer sees the inner resource closed before the outer resource closes.
An ordinary fault skips remaining cleanup
링크import std.iofunction divide(divisor: int) -> int {42 / divisor}function scenario() -> Result<int, string> {using file = (io.open("input.txt")?) {defer { io.writeLine("cleanup-observed") }divide(0)}Ok(0)}let result = scenario()
표준 출력 없음.payload
기대 결과
The division fault stops execution. The remaining defer and using cleanup are skipped under the fault cleanup rule. Standard output contains no cleanup message.
An imported protocol call executes its manual method
링크import std.io { writeLine }import remote { Item as RemoteItem }let left = RemoteItem { n: 1 }let right = RemoteItem { n: 11 }writeLine("{Eq.equals(left, right)}")
true
export record Item { n: int }impl Eq<Item> {function equals(a: Item, b: Item) -> bool { a.n % 10 == b.n % 10 }}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
true
A protocol method has ordinary generic bounds
링크protocol Echo {function echo<T: Show>(value: Self, item: T) -> T}
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Fixed defaults precede the variadic protocol tail
링크protocol Sum {function sum(value: Self, start: int = 0, ...items: int) -> int}
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Every caller uses the protocol-owned default
링크import std.io { writeLine }const ending = "!"protocol Labelled {function label(value: Self, suffix: string = ending) -> string}record Item { name: string }impl Labelled<Item> {function label(value: Item, suffix: string) -> string { value.name + suffix }}let item = Item { name: "Moss" }writeLine(Labelled.label(item))writeLine(Labelled.label(item, "?"))
Moss!
Moss?
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
Moss!Moss?
A protocol constructs a value without a receiver argument
링크import std.io { writeLine }protocol Factory {function make(value: int) -> Selffunction zero() -> Self}record Item { value: int }impl Factory<Item> {function make(value: int) -> Item { Item { value: value } }function zero() -> Item { Item { value: 0 } }}let explicit = Factory.make<Item>(9)let inferred: Item = Factory.zero()writeLine("{explicit.value}")writeLine("{inferred.value}")
9
0
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
90
Protocol calls reject named arguments during parsing
링크protocol Labelled {function label(value: Self) -> string}record Item { name: string }impl Labelled<Item> {function label(value: Item) -> string { value.name }}let item = Item { name: "Moss" }Labelled.label(value: item)
표준 출력 없음.기대 결과
A required protocol parameter cannot follow a default
링크protocol Sum {function sum(value: Self, first: int = 1, second: int) -> int}
표준 출력 없음.기대 결과
A bodyless protocol signature still declares its result
링크protocol Labelled {function label(value: Self)}
표준 출력 없음.기대 결과
Implementation binders and renamed method binders remain distinct
링크import std.io { writeLine }protocol Echo {function echo<U: Show>(value: Self, item: U) -> U}record Box<T> { value: T }impl<T> Echo<Box<T>> {function echo<V: Show>(value: Box<T>, item: V) { item }}let box: Box<int> = Box { value: 3 }writeLine(Echo.echo<Box<int>, string>(box, "ok"))let inferred: int = Echo.echo(box, 9)writeLine("{inferred}")
ok
9
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
ok9
Protocol defaults and a variadic implementation share one call plan
링크import std.io { writeLine }protocol Sum {function sum(value: Self, start: int = 10, ...items: int) -> int}record Item { offset: int }impl Sum<Item> {function sum(value: Item, start: int, ...items: int) {let mut total = value.offset + startfor item in (items) { total = total + item }total}}let item = Item { offset: 1 }writeLine("{Sum.sum(item)}")writeLine("{Sum.sum(item, 2, ...[3, 4], 5)}")writeLine("{Sum.sum(item, ...[2, 3])}")
11
15
16
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
111516
An omitted implementation result uses the protocol result context
링크protocol Choose {function choose(value: Self) -> int | string}record Item {}impl Choose<Item> {function choose(value: Item) { 7 }}let chosen: int | string = Choose.choose(Item {})
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
A generic receiver keeps its outer binder and local method binders
링크import std.io { writeLine }record Box<T> { value: T }impl<T> Box<T> {function readValue(self) -> T { self.value }function echo<U>(self, item: U) -> U { item }}let box: Box<int> = Box { value: 3 }writeLine("{box.readValue()}")writeLine(box.echo<string>("ok"))
3
ok
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
3ok
A protocol owner can give int its declared operation
링크import std.io { writeLine }protocol Labelled {function label(value: Self) -> string}impl Labelled<int> {function label(value: int) -> string { "number" }}writeLine(Labelled.label(7))
number
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
number
Different concrete type arguments select distinct conformances
링크import std.io { writeLine }protocol Mark {function mark(value: Self) -> string}record Box<T> { value: T }impl Mark<Box<int>> {function mark(value: Box<int>) -> string { "integer" }}impl Mark<Box<string>> {function mark(value: Box<string>) -> string { "text" }}let number: Box<int> = Box { value: 3 }let text: Box<string> = Box { value: "three" }writeLine(Mark.mark(number))writeLine(Mark.mark(text))
integer
text
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
integertext
Conditional derive binders correspond by position without capturing fields
링크record Box<T> derives<U: Eq> Eq<Box<U>> { value: T }let first: Box<int> = Box { value: 3 }let second: Box<int> = Box { value: 3 }let same: bool = Eq.equals(first, second)
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Conformance visibility makes a separate method export invalid
링크protocol Labelled {function label(value: Self) -> string}record Item {}impl Labelled<Item> {export function label(value: Item) -> string { "item" }}
표준 출력 없음.기대 결과
An implementation cannot introduce its own omitted argument
링크protocol Labelled {function label(value: Self, suffix: string) -> string}record Item {}impl Labelled<Item> {function label(value: Item, suffix: string = "!") -> string { suffix }}
표준 출력 없음.기대 결과
Implementation method bounds must match the declared operation
링크protocol Echo {function echo<U: Show>(value: Self, item: U) -> U}record Item {}impl Echo<Item> {function echo<V: Eq>(value: Item, item: V) -> V { item }}
표준 출력 없음.기대 결과
An array parameter does not replace a variadic tail
링크protocol Count {function count(value: Self, ...items: int) -> int}record Item {}impl Count<Item> {function count(value: Item, items: Array<int>) -> int { items.length }}
표준 출력 없음.기대 결과
An inner binder cannot be mistaken for the receiver binder
링크protocol Echo {function echo<U>(value: Self, item: U) -> U}record Box<T> { value: T }impl<T> Echo<Box<T>> {function echo<T>(value: Box<T>, item: T) -> T { item }}
표준 출력 없음.기대 결과
A concrete conformance cannot specialize an overlapping generic head
링크record Box<T> { value: T }impl<T: Eq> Eq<Box<T>> {function equals(a: Box<T>, b: Box<T>) -> bool { Eq.equals(a.value, b.value) }}impl Eq<Box<int>> {function equals(a: Box<int>, b: Box<int>) -> bool { a.value == b.value }}
표준 출력 없음.기대 결과
Different positive bounds do not prove two heads disjoint
링크protocol Mark {function mark(value: Self) -> int}record Box<T> { value: T }impl<T: Eq> Mark<Box<T>> {function mark(value: Box<T>) -> int { 1 }}impl<U: Show> Mark<Box<U>> {function mark(value: Box<U>) -> int { 2 }}
표준 출력 없음.기대 결과
A conditional derive and a manual specialization share the overlap check
링크record Box<T> derives<T: Eq> Eq<Box<T>> { value: T }impl Eq<Box<int>> {function equals(a: Box<int>, b: Box<int>) -> bool { a.value == b.value }}
표준 출력 없음.기대 결과
A transparent alias cannot create a second conformance
링크record Item {}type Alias = Itemimpl Eq<Item> {function equals(a: Item, b: Item) -> bool { true }}impl Eq<Alias> {function equals(a: Alias, b: Alias) -> bool { true }}
표준 출력 없음.기대 결과
The dependency graph rejects protocol-owner and type-owner overlap
링크import rulesimport kindslet value = 0
표준 출력 없음.export protocol Mark { function mark(value: Self) -> int }impl<T> Mark<T> { function mark(value: T) -> int { 1 } }
import rules { Mark }export record Item {}impl Mark<Item> { function mark(value: Item) -> int { 2 } }
기대 결과
Changing import order cannot choose a conformance winner
링크import kindsimport ruleslet value = 0
표준 출력 없음.export protocol Mark { function mark(value: Self) -> int }impl<T> Mark<T> { function mark(value: T) -> int { 1 } }
import rules { Mark }export record Item {}impl Mark<Item> { function mark(value: Item) -> int { 2 } }
기대 결과
An implementation cannot assume its own conditional bound
링크protocol Required { function required(value: Self) -> bool }protocol Mark { function mark(value: Self) -> int }record Box<T> { value: T }impl<T: Required> Mark<Box<T>> {function mark(value: Box<T>) -> int { 1 }}let box: Box<int> = Box { value: 3 }Mark.mark(box)
표준 출력 없음.기대 결과
기대 결과
거절 단계 check. 종료 코드가 0이 아닙니다.
protocol-call-argument-does-not-conform at
example.tpz:8:11
Pending contracts
링크Related definitions and diagnostics
링크See Functions and generics for function and bound syntax, and Records, enums and newtypes for nominal construction and declaration syntax.
Protocol implementation violates the orphan rule →
Duplicate protocol implementation →
Missing protocol conformance →
Protocol cannot be derived for this type →
Division or remainder by zero →
Variadic parameter is not final →
Wrong number of explicit type arguments →
Private type in exported surface →