* `sort(arr)` returns a sorted copy of the input * `sort!(arr)` returns the sorted original
methods that return booleans end in `?`, like `arr.sorted?`
It's just a convention, but it's a nice way to let the writer know what will happen.
> `sort!(arr)` returns the sorted original
Python has a naming convention as well: `sorted(arr)` returns a sorted copy and `arr.sort()` works in-place (and returns None). However, I've always thought it's a bit odd that one is a function and the other is a method.
For example if I have a map function that applies a function f to a sequence, should I call it map! because I might pass in a function f that mutates the input? If so then it seems like any function that takes a function as input, or any function that might call a method on an object, should get marked with ! just in case. But if I don't mark it that way then the ! marking is not as informative: I might end up with a line consisting only of non-! functions which still mutates the input.
A very common case of this is mutating versions of non-mutating methods, but (1) mutating methods (in stdlib or other idiomatic code bases) that have no non-mutating equivalent are not named with a “!”, and (2) methods are sometimes named with “!” because they do dangerous things compared to a base method that are not mutating the receiver.
Coming from a language with baked-in immutability, Python’s behavior in this regard was very difficult to get used to.