[swift-dev] Warning when "overriding" an extension method that's not in the protocol
Jesse Rusak
me at jesserusak.com
Tue Jan 5 21:52:40 CST 2016
Hi Kevin,
Thanks for your thoughts. In general, I think I’m going to put off thinking more about the more general extension-shadowing warning until the related proposal on swift-evolution is decided upon, as decisions made there will undoubtedly impact what will trigger this warning and how to resolve it.
I’ll continue to work on the more specialized warning Doug brought up.
A few more comments below for when if/when we circle back to this.
> On Jan 3, 2016, at 7:33 PM, Kevin Ballard <kevin at sb.org> wrote:
>
> On Sun, Jan 3, 2016, at 09:30 AM, Jesse Rusak wrote:
>> Some things from Kevin:
>>
>>> But the warning that Jesse was talking about, the one that was discussed in the older threads, I think is completely different. If I declare a method on my type that matches a protocol extension method, it is not safe to assume I was trying to override the (non-overridable) method. It's very likely that I'm simply providing a specialization of the method that will be called by anyone who's working with my type directly (with the acknowledgement that working with the type generically won't call my type's version).
>>
>>
>> Can I ask for examples of cases where you’d want to do this intentionally? In those cases, would moving such members (or the protocol conformance) to an extension be a hassle? The point about stored properties is one way this is awkward; are there others?
>
> The suggested way to suppress the warning wasn't for this warning. It was for the warning about trying to conform to a protocol but having a member that doesn't actually match the protocol requirements (e.g. having a CollectionType with a `func generate()` that returns a type that doesn't actually conform to `GeneratorType`).
>
> The warning we're discussing here, of attempting to override a protocol extension method even though it's not a member of the protocol, can't work with this suppression mechanism unless the warning simply doesn't work at all for subclasses who inherit the protocol from their superclass. If you inherit the protocol declaration, then you can't possibly put the protocol conformance into its own extension because you're not declaring the conformance to begin with.
My intent was that you could move the conflicting member into an extension rather than the conformance in the case when the main class declaration conforms to a protocol or inherits it from its superclass. (Same proviso about stored properties, of course.)
> Even if you ignore classes, the suppression mechanism doesn't really work for this warning anyway as it would suppress a lot of the cases that you actually want to warn about. I say that because it seems quite reasonable for people to declare things like `var last` in an extension on a type (which would trigger this suppression mechanism). This is doubly true for members declared with where clauses, because those are required to be in extensions (and can't declare protocol conformance). So e.g. if I say
>
> struct MyCollection<Base : CollectionType> : CollectionType {
> // ...
> }
>
> extension MyCollection where Base.Index : BidirectionalIndexType {
> var last: Generator.Element? {
> // ...
> }
> }
>
> then, assuming you think the warning is valid to begin with, you'd want to warn about that `var last`.
Sure, we might miss that. I will add it to the “we should try to get this” pile.
>>> My belief is that a warning in this case would end up being unwanted in a disproportionate number of cases. I believe it's better to clearly differentiate between protocol methods and extension methods and how they behave in our documentation and education for programmers than to add spurious warnings that will annoy everyone who does understand the distinction.
>>
>> How often are you doing this intentionally in your code? If it’s frequent, we should see if there’s a way to suppress it for your common cases.
>
> I don't currently have any examples of this in my code. But I've also never had any cases where the warning would have triggered either. But the standard library provides examples of this!
>
> SequenceType has an extension that declares a `var lazy`. LazySequence also declares `var lazy`. It's obviously not overriding SequenceType's `lazy` property (especially because the type is slightly different), but it is very intentionally trying to shadow it, to make it so anyone who types `foo.lazy.lazy` gets back a `LazySequence<Foo>` instead of a `LazySequence<LazySequence<Foo>>`.
>
> Same thing also happens with `SequenceType.flatMap` and `LazySequence.flatMap`.
>
> CollectionType and LazyCollection is another example. At the very least the `lazy` property is an example. I'm not sure offhand if there's any other examples with those types but I wouldn't be surprised to find that there are.
>
> Set defines a method `contains(_ element:)` that's an exact match for the SequenceType extension method `contains(_ element:)`, but that's not actually an override. It also has `indexOf(_:)` which matches CollectionType's extension method `indexOf(_:)`.
>
> There may be others, I didn't do an exhaustive search of the standard library. But these should illustrate legitimate use-cases for shadowing protocol extension methods.
Thanks for this! I will definitely be looking through the rest of the standard lib for other examples.
- Jesse
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20160105/4b20d82f/attachment.html>
More information about the swift-dev
mailing list