Revisiting SE-0177: Adding `clamped(to:)`

Correct.

3 Likes

I think @jrose's observation that this could be useful for Character weakens the argument against a method further, because you may well have a String or Substring that you know contains a single character that you want to clamp, and it would let you avoid a String → Character → String dance.

The free function has the same problems if arguments are constrained to Comparable, it is just less discoverable in some current IDE implementations. And that cuts both ways: you might say that being less discoverable is good for String but that means that it is bad for Double. So I still think “useful on every single conforming type” is the wrong criteria here, because you end up harming legitimate use cases or inventing new marker protocols just to avoid a well-defined (but perhaps not particularly useful) method from appearing in an autocomplete list.

5 Likes

It almost feels like there’s a missing language feature that would allow a type to specify if it doesn’t want a specific piece of API from a protocol it conforms to. Or even just to mark “this API that the protocol I conform to vends doesn’t really make sense on me” as a flag that the IDE could use to make decisions around autocomplete.

Obviously if there’s a new API on a protocol you don’t want to be FORCED to go back through all your types and make a type by type decision about whether to mark them. But having the ability to do it would make some API decisions a bit easier when both the type and the protocol are in your control. “This method makes sense on this protocol except for this type where it’s weird” “OK, let’s mark the type as not accepting the method.”

This would completely invalidate protocols as generic constraints, though.

7 Likes

Right. "Don't provide the API at all" would be undesirable. However, "sort this to the bottom of an IDE autocompletion popup" could actually be useful.

3 Likes

In that case it could be even more desirable with more granular enumerated annotation of API.
“Common”/“Unusal”/“Auxiliary” (or something along those lines) - some completions return way too much unusual methods. Of course, one could have an IDE that automates this based on the actual code base too, but different ways to skin a cat. I think it could be nice if any API author could do such annotations to guide vs preferred API usage sometimes.

1 Like

I think maybe the best IDE experience would be to surface the completions most applied by the user in question. Or perhaps aggregating this data across the whole user base for one language, assuming they opt in to share this data.

Either way, it might be presumptive for library authors to assume what will be the most commonly used APIs and make that determination once up front. Especially for something like the stdlib which is used in so many different contexts. Maybe it’s obvious in this case but there are many others where it’s not, so creating the ability to hardcode this assumption could be harmful.

I’m short, let’s add this to Comparable and leave it to user/IDE interactions to determine what is a commonly used API vs not.

2 Likes

Personally, I’d like to see

extension Comparable {
  func clamped(to bounds: RangeExpression<Self>) -> Self
}

However, I don’t think that is possible, because of how RangeExpression and protocols inheriting it are designed. To allow it, and things like it, you’d need to have the ability to tell whether an element is greater than or less than the range.

In theory, the ideal approach there is to define protocols as broadly as possible. The standard library has a lot of good examples, such as AdditiveArithmetic.

The main obstacle, in my opinion, is namespace pollution: protocols are restricted to the global scope, so having a lot of tiny protocols can be problematic. Honestly, I don’t understand why they have that limitation.

If you ever find yourself wishing you could partially conform to a protocol, that’s arguably an indication the protocol should be broken into pieces. Conversely, if you ever find yourself wishing a protocol was more capable, that’s a sign there should be a narrower protocol extending it.

1 Like