@@ -353,35 +353,71 @@ Standard library documentation lives in the source code. The generated markdown
353353file can be found
354354[ here] ( https://github.com/p7g/c-bytecode-vm/blob/master/docs/stdlib.md ) .
355355
356- Here are some idioms that have appeared in the standard library:
356+ Here are some patterns that have appeared in the standard library:
357357
358358### Iteration
359359
360- This language has no generators, nor any built-in iteration protocol. The way
361- this is done in the standard library (see the [ iter ] module) is using closures .
360+ Using [ traits ] , the [ iter ] module defines an iteration protocol. This protocol
361+ involves 2 traits: ` Iterable ` and ` Iterator ` .
362362
363- [ iter ] : https://github.com/p7g/c-bytecode-vm/blob/main/lib/iter.cb
363+ [ traits ] : /blob/main/lib/trait.cb
364+ [ iter ] : /blob/main/lib/iter.cb
364365
365- This is easiest to illustrate with an example:
366- ``` js
367- function range (to ) {
368- let i = 0 ;
366+ The ` Iterable ` trait makes an object iterable (as the name suggests). It has a
367+ single method called ` iter(self) ` that must return an ` Iterator ` . Objects of any
368+ type that implements this trait can be passed as the iterable argument to any
369+ function in the ` iter ` module.
370+
371+ An ` Iterator ` object is a stateful iterator with a ` next(self) ` parameter, which
372+ must return the next item in the sequence.
373+
374+ Here's an example of both:
375+
376+ ``` c++
377+ struct Range { start, stop, step }
378+ struct RangeIterator { range, i }
369379
370- return function next () {
371- if (i == to) {
372- return null ;
380+ trait::impl(iter::Iterable, Range, struct {
381+ function iter(self) {
382+ return RangeIterator { range = self }
383+ }
384+ });
385+
386+ trait::impl(iter::Iterator, RangeIterator, struct {
387+ function next(self) {
388+ if (self.i == null) {
389+ self.i = self.range.start;
373390 }
374- let val = i;
375- i += 1 ;
376- return val;
377- };
378- }
379391
380- test:: assert (iter:: collect (range (10 )) == [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]);
392+ if (self.i >= self.range.end) {
393+ return iter::STOP;
394+ }
395+
396+ let { i } = self;
397+ self.i += self.range.step;
398+ return i;
399+ }
400+ });
401+
402+ function range (start, stop=null, step=null) {
403+ if (stop == null) {
404+ return Range { start = 0, stop = start, step = 1 };
405+ } else {
406+ if (step == null) {
407+ step = 1;
408+ }
409+ return Range { start = start, stop = stop, step = step };
410+ }
411+ }
381412```
382413
383- Using constructs like these, iteration can be performed like in JavaScript:
384- ``` js
414+ It's common to implement `iter::Iterable` for any type that also implements
415+ `iter::Iterator`; that way you can use existing iterators as arguments for
416+ `iter` functions.
417+
418+ Once you have an object that implements the iteration protocol, you can use it
419+ like this:
420+ ```c++
385421iter::foreach(range(10), function (n) {
386422 println(n);
387423});
0 commit comments