It's also worth noting that if the list of buffers is static then you still have the same equivalency as now i become the target of append (acting like a pointer). so<code>i.append(str) <=> append(i, str)<br></code>
to access the i-th buffer and append str to it. The buffer access and bounds checking have been internalized. If the list of buffers is a fixed size, you can then "unroll" each entry into:<code>append-1(str)<br>append-2(str)<br>append-3(str)<br>.<br>.<br>.<br></code>
So this is kinda two tricks mashed together (OOP with monomorphization and inlining).