11import _arraylist_impl;
22import _array;
3+ import docs;
34import structs;
45
6+ let docs = docs::module("trait", "
7+ A trait is a reusable set of methods that can be used to extend the behavior of
8+ a type. It's an interface that defines a contract that must be implemented by
9+ any type that wishes to support the trait. Any objects that implement the trait
10+ can be converted to a _trait object_, which can be used to call the methods
11+ defined by the trait.
12+
13+ For example, you can define a `Printable` trait with a method `print()`:
14+ ```c++
15+ let Printable = trait::new(\"Printable\", [trait::method(\"print\")]);
16+
17+ trait::impl(Printable, MyType, struct {
18+ function print(self) {
19+ println(\"MyType \", self.value);
20+ }
21+ });
22+
23+ # Both equivalent:
24+ Printable.print(MyType { value = 42 });
25+ trait::cast(Printable, MyType { value = 42 }).print();
26+ ```
27+ ");
28+
529export struct TypeError { message }
630
731struct Method { name, arity }
@@ -11,6 +35,8 @@ export function method(name) {
1135 return Method { name = name };
1236}
1337
38+ docs.add("function", "method(name)", "Create a trait method declaration for use with `trait::new()`");
39+
1440function concat(a1, a2) {
1541 let a1len = _array::length(a1),
1642 a2len = _array::length(a2);
@@ -73,6 +99,14 @@ export function new(name, methods) {
7399 return trait;
74100}
75101
102+ docs.add(
103+ "function",
104+ "new(name, methods)",
105+ "Create a new trait with the given name and methods.
106+
107+ Any implementors must define all methods, though the signature of the methods is
108+ not checked.");
109+
76110export function cast(trait, obj) {
77111 if (!is_trait(trait)) {
78112 throw TypeError {
@@ -83,10 +117,32 @@ export function cast(trait, obj) {
83117 return instantiate_traitobject(trait, obj);
84118}
85119
120+ docs.add(
121+ "function",
122+ "cast(trait, obj)",
123+ "Create a trait object for the given trait and object.
124+
125+ `obj` must be an object that implements the trait. Any trait methods can be
126+ called directly on the trait object.");
127+
86128export function primitive(ty) {
87129 return Primitive { type = ty };
88130}
89131
132+ docs.add(
133+ "function",
134+ "primitive(typename)",
135+ "Used to specify a primitive type like `\"string\"` as the implementor of a trait. Example:
136+
137+ ```c++
138+ trait::impl(ToString, trait::primitive(\"string\"), struct {
139+ function to_string(self) {
140+ return self;
141+ }
142+ });
143+ ```
144+ ");
145+
90146export function impl(trait, for_, impl_struct) {
91147 let for_type = get_type(for_);
92148 if (get_impl(trait, for_type)) {
@@ -126,6 +182,22 @@ export function impl(trait, for_, impl_struct) {
126182 _arraylist_impl::push(trait._impls, impl);
127183}
128184
185+ docs.add(
186+ "function",
187+ "impl(trait, type, implementation)",
188+ "Implement a trait for some type.
189+
190+ The `implementation` should be a struct containing methods for each method
191+ defined in the trait. For example:
192+
193+ ```c++
194+ trait::impl(ToString, MyType, struct {
195+ function to_string(self) {
196+ # ...
197+ }
198+ });
199+ ```");
200+
129201export function downcast(traitobject) {
130202 try {
131203 return traitobject._obj;
@@ -136,6 +208,8 @@ export function downcast(traitobject) {
136208 }
137209}
138210
211+ docs.add("function", "downcast(traitobject)", "Retrieve the underlying object from a trait object.");
212+
139213export function implements(obj, trait) {
140214 if (!is_trait(trait)) {
141215 throw TypeError {
@@ -149,6 +223,15 @@ export function implements(obj, trait) {
149223 }
150224}
151225
226+ docs.add(
227+ "function",
228+ "implements(obj, trait)",
229+ "Check if an object implements a trait.
230+
231+ If `obj` is a trait object, `implements` will return true if its trait is
232+ `trait`. Otherwise return true if `obj` implements the trait and could be cast
233+ to a trait object for `trait`.");
234+
152235function is_trait(trait) {
153236 try {
154237 return trait._is_trait;
0 commit comments