~sircmpwn/harelang.org

468a4ca8aec8d8b40526aed54ad2ec95b1783e13 — Lorenz (xha) 2 months ago 8c2fee2
language introduction: explain for-each

with lots of feedback & suggestions from Byron

Co-authored-by: Byron Torres <b@torresjrjr.com>
Signed-off-by: Lorenz (xha) <me@xha.li>
1 files changed, 81 insertions(+), 10 deletions(-)

M content/tutorials/introduction.md
M content/tutorials/introduction.md => content/tutorials/introduction.md +81 -10
@@ 1141,7 1141,7 @@ sections:
      Getting values out of match expressions is likely to be the most common
      use of this feature in your code. But, keep `yield` in your tool belt and
      you might end up using it to solve other problems every now and then, too.
- title: for loops
- title: For loops
  sample: |
      use fmt;



@@ 1183,6 1183,77 @@ sections:
      	// ...
      };
      ```
- title: For-each loops
  sample: |
      use fmt;

      const items = [
      	"apple",
      	"banana",
      	"carrot",
      ];
      let items_counter = 0z;

      // iterator function
      fn next() (str | done) = {
      	if (items_counter < len(items)) {
      		items_counter += 1;
      		return items[items_counter - 1];
      	};
      	return done;
      };


      export fn main() void = {
      	// for-each value
      	for (let item .. items) {
      		fmt::printfln("{}", item)!;
      	};

      	// for-each reference
      	for (let item_ptr &.. items) {
      		fmt::printfln("{} = {}", item_ptr, *item_ptr)!;
      	};

      	// for-each iterator
      	for (let item => next()) {
      		fmt::printfln("{}", item)!;
      	};
      };

  details: |
      In addition to the `for` loops described above, there are also for-each
      loops, which make common patters a lot simpler. These have no condition or
      afterthought, just a binding. The are three forms of for-each loops in
      Hare: for-each value, for-each pointer and for-each iterator.

      The first for-each loop (for-each value) iterates over every element of
      the `items` array by value. Each element is copied to the binding. This is
      good for small sized values or if you don't want mutate the slice or array
      directly.

      The second for-each loop iterates over every element of the `items` array
      by reference. Here, only a pointer to each element is assigned. This is
      useful if you want to mutate the array/slice itself or want to avoid
      copies beacuse the values are too big. The example prints the pointer to
      the element and then the element itself.

      The initializer of the binding is a special "iterator" function whose
      return type is a tagged union which includes the `done` type. This
      function is called each iteration and it's return value, is checked. If
      the value's type is `done`, the loop is terminated. Otherwise, the value
      is assigned, and its type is that of the return type minus `done`. In this
      case, that would be `str`.

      A lot of standard libary functions make use of the `done` type or aliases
      of it. You can use a for-each iterator loop in these cases, or create some
      useful functions yourself.

      <div class="alert">
        <strong>Note:</strong> It is not possible to `insert`, `delete`, `free`
        and `append` to the slice beeing iterated over. It is encouraged to
        use normal for loops for this use case instead.
      </div>
- title: Flow control
  sample: |
      use fmt;


@@ 1195,11 1266,11 @@ sections:
      		"is",
      		"cool!",
      	];
      	for (let i = 0z; i < len(items); i += 1) {
      		if (items[i] == "Hare") {
      	for (let item .. items) {
      		if (item == "Hare") {
      			continue;
      		};
      		fmt::println(items[i])!;
      		fmt::printfln(item);
      	};
      };
  details: |


@@ 1558,8 1629,8 @@ sections:
      	sort::strings(lines);

      	fmt::println("Your strings, sorted:")!;
      	for (let i = 0z; i < len(lines); i += 1) {
      		fmt::println(lines[i])!;
      	for (let line .. lines) {
      		fmt::printfln(line)!;
      	};
      };
  details: |


@@ 1595,8 1666,8 @@ sections:

      	let buf: [10]str = [""...];
      	let lines = buf[..0];
      	defer for (let i = 0z; i < len(lines); i += 1) {
      		free(lines[i]);
      	defer for (let line .. lines) {
      		free(line);
      	};

      	for (true) {


@@ 1622,8 1693,8 @@ sections:
      	sort::strings(lines);

      	fmt::println("Your strings, sorted:")!;
      	for (let i = 0z; i < len(lines); i += 1) {
      		fmt::println(lines[i])!;
      	for (let line .. lines) {
      		fmt::println(line)!;
      	};
      };
  details: |