Right now, providing a method marked with @available(*, unavailable) doesn't 
actually prevent anyone from calling that method if the type in question 
inherits the same method from any protocol. Instead the unavailable method is 
ignored. This is in contrast with overriding a method from your superclass, 
where the @available(*, unavailable) annotation works just fine (as long as 
you're invoking the method with the correct compile-time receiver type).

I believe this should be changed such that if the type that declares the 
@available(*, unavailable) method inherits from a protocol, it blocks the 
ability to resolve that method to the protocol version. On the other hand, if a 
class declares an unavailable method, and a subclass conforms to a protocol 
that provides the method (and the base class does not conform to the protocol), 
the protocol method should be accessible as it's not "blocked" by the parent 
class.

This logic should be the same for methods declared in the protocol as well as 
methods provided by extensions to the protocol (as long as the extension is 
visible to the type that declares the @available(*, unavailable) method).

The rationale for doing this is twofold:

1. If a particular implementation of a protocol can't actually support one of 
the extension methods, for example an infinite sequence can't possibly support 
an eager map() or reduce() (as it would result in an infinite loop), the 
concrete type could declare the method as @available(*, unavailable, 
message="this would loop infinitely, try the lazy version"). Any code that 
attempts to call the method on the concrete type would then provide a nice 
compile-time error instead of failing at runtime. Of course, any code that 
calls the method on a generic type <T: Proto> would not be aware of this, but 
there's not much we can do about that.

2. Protocols like LazySequenceType that provide alternate versions of inherited 
methods may want to mark the inherited method as unavailable. In Swift 2.1, the 
code `someCol.lazy.filter(pred).first` compiles just fine, but it's not 
actually lazy; because SequenceType does not have a property `first`, the call 
to `.filter(pred)` actually resolves to the eager version inherited from 
SequenceType. This is likely to be very surprising to users (who may not even 
be aware of their accidental O(N) code), and so it would make sense for 
LazySequenceType to mark the inherited eager versions of map/filter/etc as 
unavailable.

-Kevin Ballard
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to