Can't call `each` on `retro` with *some* functions

Paul Backus snarwin at gmail.com
Sun Dec 14 12:43:57 UTC 2025


On Sunday, 14 December 2025 at 12:32:23 UTC, yabobay wrote:
> I have this piece of code:
>
> ```d
> import std.stdio;
> import std.container : SList;
> import std.algorithm : each;
> import std.range : retro;
>
> void frob(const string s) {
>     SList!char ll;
>     s.retro.each!(c => ll.insertFront(c));
>     foreach (c; ll)
>         c.write;
>     writeln;
> }
> ```
>
> If i remove the call to `retro`, it compiles just fine. If i 
> change `each`'s operation to something like `writeln`, it 
> compiles just fine. But unchanged, this program will not 
> compile and will give this error:
>
> ```
> test.d:8:12: error: none of the overloads of template 
> ‘test.frob.each!((c) => ll.insertFront(c)).each’ are callable 
> using argument types ‘!()(Result!())’
>     8 |     s.retro.each!(c => ll.insertFront(c));
>       |            ^
> /usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include/d/std/algorithm/iteration.d:912:17: note: Candidates are: ‘each(Range)(Range r)’
>   with `Range = Result!()`
>   must satisfy one of the following constraints:
> `       isRangeIterable!Range
>        __traits(compiles, typeof(r.front).length)`
>   912 |     Flag!"each" each(Range)(Range r)
>       |                 ^
> ```

This is caused by [autodecoding][1], a feature of the standard 
library where strings are automatically converted into Unicode 
code points when used as ranges.

Because UTF-8 is a variable-length encoding, this means that when 
a UTF-8 `string` is used as a range, it does not have a `.length` 
property (read the linked article for a more thorough 
explanation).

You can work around this using `std.utf.byCodeUnit` to treat the 
string as a range of bytes instead of a range of code points:

```d
import std.utf : byCodeUnit;

s.byCodeUnit.retro.each!(...); // No error
```

[1]: https://jackstouffer.com/blog/d_auto_decoding_and_you.html


More information about the Digitalmars-d-learn mailing list