Naming of `rotate(at:)`

There are two possible operations with a grid: rotateRows and rotateColumns. Wouldn’t it be better to name them that?

Probably, but we’re discussing in this thread a generic algorithm which will be applied to all MutableCollections—we should prefer names which aren’t potentially inaccurate/misleading when applied to specific conforming types.

1 Like

I would think that a generic rotate when applied to a grid is already confusing—you’d have to check the documentation to be sure what it did.

Agreed. But there’s a difference between a name which conveys inaccurate or misleading information, and one which simply does not convey enough information. IMO, rotate(toStartAt:) falls into the second category—there’s no obvious “start” or “end” to a grid, so the name naturally indicates that you should check the documentation to determine its behavior. OTOH, rotate(leftBy:) has a much more suggestive meaning when applied to a grid, which, depending on the precise semantics, is simply wrong.

ETA: You could probably contrive a type for which rotate(toStartAt:) is misleading, but I expect such a type would become misleading with respect to the basic semantics of the collection hierarchy (e.g., startIndex).

Putting aside the second dimension for a minute, the start of a grid would unambiguously be that which has the smallest index (0) versus that which has the greatest index. Left and right wouldn't work here because we think of this array as vertical, but start is still unambiguous.

1 Like

Of course, but that’s circular. If I tell you I have a grid of elements (even if I told you that it was modeled as a Collection of rows), you could plausibly expect “the row with index 0”. There’s nothing inherent to a grid that favors top-to-bottom ordering over bottom-to-top—it’s just convention.

MATLAB goes pretty explicit with "circular shift", since in a programming language heavily vector-matrix-tensor based, rotating a vector has a defined geometrical meaning.

func circularlyShift(by offset: Int) -> Self { ... }

I don't personally agree with the ambiguity of a rotate(by offset: Int) name, however.
In Collections we have a defined offsetting direction, the one going toward increasing indices: the Collection.formIndex(_:offsetBy:) method is built upon that.

I’m not sure that the mere use of offset does much to resolve the ambiguity—there’s still the question of whether rotating “by” offset moves the current starting element to offset, or moves the element currently at offset to the start. IMO both are plausible interpretations.

This ambiguity doesn’t arise with formIndex(_:offsetBy:) because it’s clear that we’re starting with the provided index and applying the offset from there. Using a slightly different preposition like rotate(to:) is a minor improvement, but I think adding the few extra characters to get the totally unambiguous rotate(toStartAt:) is completely worth it.

2 Likes

Respectfully, I disagree. It even sound wrong rotate-toStartAt, maybe rotate-startingAt but even then I still much prefer rotate-At.

What about convenient method to push collection to right? Did anybody fork it?
array.rotate(toStartAt: -1) now it throws the error Can't form Range with upperBound < lowerBound. I just want to push these four building blocks to right at four positions,

Summary

[:black_medium_square:︎, :black_medium_square:︎, :black_medium_square:︎, :black_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎]
[:white_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎, :black_medium_square:︎, :black_medium_square:︎, :black_medium_square:︎, :black_medium_square:︎, :white_medium_square:︎, :white_medium_square:︎]

this is a very natural desire. And now I must write array.rotate(toStartAt: 6), which is somewhat confusing. Because if index type of the rotating collection is Int, is just enough to calculate
array.rotate(toStartAt: array.count - insertingarray.count). But task became nontrivial if Index is just Strideable.