Correct.
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.
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.
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.
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.
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.
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.