Skip to content

Commit 3f8a743

Browse files
committed
document traits
1 parent 7d1ffa6 commit 3f8a743

3 files changed

Lines changed: 168 additions & 0 deletions

File tree

docs/stdlib.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Index:
44
- [docs](#docs-module)
5+
- [trait](#trait-module)
56
- [array](#array-module)
67
- [list](#list-module)
78
- [math](#math-module)
@@ -53,6 +54,89 @@ The interface for a documentation generator.
5354

5455
Create an object to document members of a module.
5556

57+
## trait module
58+
59+
60+
A trait is a reusable set of methods that can be used to extend the behavior of
61+
a type. It's an interface that defines a contract that must be implemented by
62+
any type that wishes to support the trait. Any objects that implement the trait
63+
can be converted to a _trait object_, which can be used to call the methods
64+
defined by the trait.
65+
66+
For example, you can define a `Printable` trait with a method `print()`:
67+
```c++
68+
let Printable = trait::new("Printable", [trait::method("print")]);
69+
70+
trait::impl(Printable, MyType, struct {
71+
function print(self) {
72+
println("MyType ", self.value);
73+
}
74+
});
75+
76+
# Both equivalent:
77+
Printable.print(MyType { value = 42 });
78+
trait::cast(Printable, MyType { value = 42 }).print();
79+
```
80+
81+
82+
### function `implements(obj, trait)`
83+
84+
Check if an object implements a trait.
85+
86+
If `obj` is a trait object, `implements` will return true if its trait is
87+
`trait`. Otherwise return true if `obj` implements the trait and could be cast
88+
to a trait object for `trait`.
89+
90+
### function `downcast(traitobject)`
91+
92+
Retrieve the underlying object from a trait object.
93+
94+
### function `impl(trait, type, implementation)`
95+
96+
Implement a trait for some type.
97+
98+
The `implementation` should be a struct containing methods for each method
99+
defined in the trait. For example:
100+
101+
```c++
102+
trait::impl(ToString, MyType, struct {
103+
function to_string(self) {
104+
# ...
105+
}
106+
});
107+
```
108+
109+
### function `primitive(typename)`
110+
111+
Used to specify a primitive type like `"string"` as the implementor of a trait. Example:
112+
113+
```c++
114+
trait::impl(ToString, trait::primitive("string"), struct {
115+
function to_string(self) {
116+
return self;
117+
}
118+
});
119+
```
120+
121+
122+
### function `cast(trait, obj)`
123+
124+
Create a trait object for the given trait and object.
125+
126+
`obj` must be an object that implements the trait. Any trait methods can be
127+
called directly on the trait object.
128+
129+
### function `new(name, methods)`
130+
131+
Create a new trait with the given name and methods.
132+
133+
Any implementors must define all methods, though the signature of the methods is
134+
not checked.
135+
136+
### function `method(name)`
137+
138+
Create a trait method declaration for use with `trait::new()`
139+
56140
## array module
57141
58142
Functions for working with arrays.

lib/trait.cb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,31 @@
11
import _arraylist_impl;
22
import _array;
3+
import docs;
34
import 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+
529
export struct TypeError { message }
630

731
struct 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+
1440
function 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+
76110
export 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+
86128
export 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+
90146
export 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+
129201
export 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+
139213
export 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+
152235
function is_trait(trait) {
153236
try {
154237
return trait._is_trait;

scripts/generate-documentation

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ import path;
2323
import re;
2424
import string;
2525
import test;
26+
import trait;
2627

2728
docs::generate(docs::print_generator(docs::single_page_markdown()));

0 commit comments

Comments
 (0)