On Mon, Dec 14, 2015 at 4:47 PM, Paul Cantrell via swift-evolution < swift-evolution@swift.org> wrote:
On Dec 14, 2015, at 1:37 AM, Dave Abrahams <dabrahams@apple.com> wrote:
func maxY(p1: P, p2: P) -> Int {
return max(p1.y, p2.y) // No problems here!
}
…right?
Ah, but then you have the situation that P doesn't conform to P (it
doesn't have an x that you can access). In my opinion that is just too
weird an idea to be usable.
Personally, I have always thought that protocols intended to be used as
unbound existentials (not P<A: Int>, just plain P) are different beasts
entirely from the kind used as generic constraints and should be explicitly
declared as such—I don't think I've ever seen a protocol that is well-used
in both ways; if you have counterexamples I'd love to see them. In
"existential protocols," declaring an associated type or creating a self
requirement would be an error at the point of declaration.
IMHO, it’s an artificial distinction that makes sense only if you’re
acclimated to Swift’s current behavior.
There are plenty of situations where you really do want a generic type in
the protocol, but you nonetheless find yourself in situations where you
care only about the parts of the protocol that don’t depend on that generic
type.
Here’s an example, pared down a lot but taken from an actual project:
protocol Request
{
typealias ContentType
func onCompletion(callback: (ContentType?, ErrorType?) -> Void)
func onSuccess(callback: ContentType -> Void)
func onNewData(callback: ContentType -> Void)
func onFailure(callback: ErrorType -> Void)
func cancel()
}
struct RequestBatch
{
var requests: [Request] // Sadness. Despair. DOOOOM.
func cancelAll()
{
for request in requests
{ request.cancel() }
}
}
The current Swift solution is either to ditch the type safety of
ContentType, or split Request into two protocols. The latter makes the API
hard to read, and may decouple related protocol requirements that don’t
make sense independently.
On Dec 14, 2015, at 1:40 AM, ilya <ilya.nikokoshev@gmail.com> wrote:
You can achieve the same result more cleanly with
func maxY<T:P, U:P>(p1:T, p2: U) -> Int {
return max(p1.y, p2.y) // No problems here!
}
True, but this doesn’t generalize to other contexts, e.g.
RequestBatch.requests above.
Conceptually, at least to me, a protocol describes a set of related
capabilities that together add up to a meaningful behavior. Whether some of
those capabilities share a generic type is incidental, and does not
fundamentally change the nature of a protocol. Protocols should be
protocols.
Java can do this via the <?> syntax:
interface Request<ContentType>
{
void onCompletion(CompletionCallback<ContentType> callback);
void onSuccess(SuccessCallback<ContentType> callback);
void onNewData(SuccessCallback<ContentType> callback);
void onFailure(FailureCallback<ContentType> callback);
void cancel();
}
class RequestBatch
{
private List<Request<?>> requests;
public void cancelAll()
{
for(Request<?> request: requests)
{ request.cancel(); }
}
}
And yes, “Java can do it” is a deliberate provocation! :P
Cheers,
Paul
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
https://innig.net • @inthehands • http://siestaframework.com/
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution