-
-
Notifications
You must be signed in to change notification settings - Fork 0
Functions Generics And Traits
trait Named {
fn name(self: &Self) -> Str
}
impl Named for User {
fn name(self: &User) -> Str { self.name }
}
Status: functions, recursion, first-class function values, defaults, generic types and functions, parameters of higher kind, trait bounds, implementations, qualified and method calls, and dynamic trait values are checked and interpreted.
fn add(a: Int, b: Int = 1) -> Int { a + b }
fn apply(value: Int, transform: fn(Int) -> Int) -> Int { transform(value) }
Calls evaluate the callee and arguments left-to-right. Default expressions may use module constants and earlier parameters, not caller locals or later parameters. Recursion is implemented; tail-call optimization is not promised.
import Std.Order {Ord}
fn smaller[T: Ord](left: T, right: T) -> T {
if left.before(&right) { left } else { right }
}
Type parameters are explicit on declarations. Multiple constraints use +. Explicit type
arguments use name[Type](arguments); omitted arguments are inferred when constraints determine
them.
A parameter normally stands for a type. A parameter written with holes stands for a type constructor — something that becomes a type once it is given arguments. The holes say how many it takes, and they are written in the declaration rather than inferred from use.
T // a type
F[_] // a constructor taking one argument, as Array or Option
F[_, _] // a constructor taking two, as Map or Result
This is what lets a trait be written over the container itself rather than over what it holds:
export trait Mappable[F[_]] {
fn mapped[A, B](self: &F[A], transform: fn(A) -> B) -> F[B]
}
impl Mappable[Array] for Array {
fn mapped[A, B](self: &Array[A], transform: fn(A) -> B) -> Array[B] {
List.map(self, transform)
}
}
A function may then take "some container" rather than one it was written for:
export fn over[F[_]: Mappable, A, B](values: &F[A], transform: fn(A) -> B) -> F[B] {
values.mapped(transform)
}
Two rules keep this small. An implementation names a bare constructor — Array, not
Array[Int] — and a constructor is never partially applied. And an unbounded parameter of higher
kind stays opaque: it says how many arguments its constructor takes and never which constructor
it is, so nothing may be read out of it.
Because arity is declared, applying a parameter that did not ask for arguments is reported where it
is written. fn swap[F](value: F[Int]) -> F[Str] is E3038, which names the parameter and points
at the two things a reader writing it means: a generic type they can name, or a second parameter.
Std.Mappable is the standard library's use of this. It is deliberately small — one member — and
exists to show the mechanism carries its weight rather than to import a hierarchy of abstractions.
Traits declare behavior without stored state. The orphan rule requires the current module to own the trait or the nominal implementing type. Exact normalized duplicate heads, including alpha-equivalent generic heads, are rejected. General unification-based overlap detection is not implemented. Inherent methods take precedence; ambiguity among applicable visible methods requires qualification.
Named.name(&user)
user.name()
Trait defaults can call other trait methods through Self. Generic trait parameters and
implementation-specific associated result behavior are preserved during selection.
fn render(value: dynamic Named) -> Str { value.name() }
dynamic Trait stores a value whose concrete type is not named at the use site and dispatches
through its checked implementation. Ordinary bounded generics remain statically selected.
There is no native monomorphization or ABI yet because native code generation is not implemented. The interpreter provides the observable trait and function behavior described here.
- Modules And Imports
- Values, Bindings, And Blocks
- Types And Inference
- Records, Sums, And Tuples
- Functions Generics And Traits
- Pattern Language
- Control Flow And Patterns
- Iteration And Loops
- Failure And Propagation
- Numbers And Collections
- Sets Maps And Sequences
- Keyed Structures
- Trees And Hierarchies
- Standard Library
- Output Formatting And Testing
- Tasks And Scopes
- Compile-Time Evaluation
- Typed Macros
- References And Unsafe
- Worked Programs