Rust libraries, especially the standard library, often end up having multiple slightly different variants of methods:
try_,_checked/_unchecked_ref,_mut, and occasionally_ptr,_mut_ptr,_drop- split and search ×
- forward and
reverse - exclusive and
_inclusive - unlimited, limited to
n, and_once
- forward and
_start/_end,_prefix/_suffix- sort ×
- stable/
_unstable _byclosure,_by_key,_by_cached_key, and_floats
- stable/
- collections ×
_inallocator_uninit,_zeroed- fallible
try_ _with_capacity(_and_hasher)_within_capacity_entry/_key_value
_arrayor_slice(sometimes_exact)[u8]vs_str,_os_str,_ascii,_wideor_with_nul- immediate value vs
_with/_then/_else wrapping_,saturating_,overflowing_,strict_,unbounded_,algebraic_,carrying_and_signed,_eulicd.le_/ne_/be_bytesmake_/_in_placevs copyto_/into_- rayon has
_init/_with/_any/_first/_last,_context,in_place_and_fifo - SIMD has type × width × low/high/single/vector/horizontal/unaligned/masked
- Async has
_blocking, and sometimes_send/_localor_on(handle).
So far Rust survives doing nothing about it, but that's not ideal. This isn't a one-time accident, this is how Rust de-facto works. Some duplication (like _mut vs ref vs owned) is unavoidable. The standard library won't ever have fewer methods, and it's likely it will only grow.
Adding a degree of flexibility (fallible allocation, non-UTF8 stings, float size, closure callback, unchecked) can easily double the API size, and this compounds exponentially when the API supports multiple cross-cutting aspects like these.
The fear of multiplying API surface to a problematic size causes pushback against adding more flavors of methods, at cost of losing more specific methods that could have better performance, error handling, usability, or additional features.
I think it's worth considering what can be done in the language, libraries, tooling, design patterns, etc. to either reduce the need to multiply methods, or to improve working with bunches of similar methods to make it a non-issue.