... this sums up as 2 suffixes indicating 2 dimensions:
i for enumerate-like iterations
_rev for reversed iterations
... and generates 2^2 = 4 variants.
This API design style is a bad smell for me, since it severely limits extensibility. For example, adding a variant of cancellation with this signature:
/// Iterates over the elements of the array. Return `True` for cancelling the iteration for remaining elements.
pub fn iter_with_break(self: Array[T], f: (T) -> Bool) -> Unit
Then all the existing variants must add _with_break suffix, bloating API to 2^3 = 8 variants:
iter(self, (T)->())
iter_with_break(self, (T)->Bool)
iter_rev(self, (T)->())
iter_rev_with_break(self, (T)->Bool)
iteri(self, (Int, T)->())
iteri_with_break(self, (Int, T)->Bool)
iter_revi(self, (Int, T)->())
iter_revi_with_break(self, (Int, T)->Bool)
As seen from this example, any new variants will cause the code bloats by O(2^n) and making it unable to maintain very fast.
Array
has the following methods to iterate:iter(self, (T)->())
iter_rev(self, (T)->())
iteri(self, (Int, T)->())
iter_revi(self, (Int, T)->())
... this sums up as 2 suffixes indicating 2 dimensions:
i
for enumerate-like iterations_rev
for reversed iterations... and generates
2^2 = 4
variants.This API design style is a bad smell for me, since it severely limits extensibility. For example, adding a variant of cancellation with this signature:
Then all the existing variants must add
_with_break
suffix, bloating API to2^3 = 8
variants:iter(self, (T)->())
iter_with_break(self, (T)->Bool)
iter_rev(self, (T)->())
iter_rev_with_break(self, (T)->Bool)
iteri(self, (Int, T)->())
iteri_with_break(self, (Int, T)->Bool)
iter_revi(self, (Int, T)->())
iter_revi_with_break(self, (Int, T)->Bool)
As seen from this example, any new variants will cause the code bloats by
O(2^n)
and making it unable to maintain very fast.