[swift-evolution] [swift-evolution-announce] [Review #2] SE-0091: Improving operator requirements in protocols

Xiaodi Wu xiaodi.wu at gmail.com
Wed Jul 13 13:49:34 CDT 2016


On Wed, Jul 13, 2016 at 1:14 PM, Douglas Gregor via swift-evolution <
swift-evolution at swift.org> wrote:

>
> On Jul 12, 2016, at 10:35 AM, Jordan Rose <jordan_rose at apple.com> wrote:
>
> [Proposal:
> https://github.com/apple/swift-evolution/blob/master/proposals/0091-improving-operators-in-protocols.md
> ]
>
> I definitely think this is an improvement over the last version! Nice
> work, Tony and Doug.
>
> I *am* a little confused about the implementation, though. The proposal
> says this:
>
> Instead, Swift should always perform operator lookup universally such that
> it sees all operators defined at either module scope or within a
> type/extension of a type. This gives us the syntactic
> improvements immediately and the natural Swift thing of defining your
> functionality within the type or an extension thereof just works.
>
>
> and then later says
>
> Therefore, we can achieve the performance improvements by making that
> insight part of the semantic model: when we find all operators, we also
> find the operators in the protocols themselves. The operators in the
> protocols are naturally generic.
>
>
> Then, we say that we do not consider an operator function if it implements
> a protocol requirement, because the requirement is a generalization of all
> of the operator functions that satisfy that requirement. With this rule,
> we’re effectively getting the same effects as if users had
> declared trampoline operators, but it's automatic.
>
>
> How do we know if an operator function implements a protocol requirement?
>
>
> Well, we can track it explicitly in the modules that define the protocol
> and that define conformances of specific types to the protocol.
> Alternatively, we try the protocol requirements *first*. Once we’ve
> inferred the ‘Self’ type of the protocol (which is part of trying the
> protocol requirement), we can look up a conformance and the witness to see
> which witnesses should no longer be considered.
>
> What happens when an operator function implements a protocol requirement,
> but is also more general than that?
>
>
> *Right now*, it’s only really possible when you’re using a global generic
> operator, because we require exact type matches between requirements and
> witnesses. If/when we allow the witness to be a supertype of the
> requirement, you’ll start to see more of the semantic effects of this
> model, because shadowing the witness with the requirement can reject code
> that is well-formed now.
>
> That’s why the shadowing behavior needs to be part of the semantic model.
> Implementation will let us settle the exact details so we can state those
> semantics more precisely.
>
> And if we do find the implementation in the protocol, what conformance do
> we use to invoke the function when the types involved aren’t all 'Self’?
>
>
> If there isn’t a reference to ‘Self’, type inference for the use of the
> protocol requirement will fail.
>
>
> I still prefer the rule that says we perform lookup into the left type and
> the right type, then fall back to top-level scope for backwards
> compatibility.
>
>
> We thought about it a lot, and it’s not implementable in a way that’s
> consistent with type inference, because one of the left or right types
> might not be known yet, and you also need to consider the context type for
> something like, e.g.,
>
> let x: UInt = 1 + 2
>
>
>
>
> Separately from the lookup rules, I’m still unhappy with the class
> problem. The proposal states this:
>
> We expect classes to implement the static operators in the protocol using
> `class` methods instead of `static` methods, which allows subclases to
> override them.
>
>
> However, if lookup only finds the method in the protocol, it’s unclear
> whether this will call a conforming class's method, a static type’s method,
> or a dynamic type’s method; if it’s not the last, it’s hardly an
> “override”. I maintain that this is the wrong behavior for any class
> hierarchy that *does* include heterogeneous operations, including
> "assignment operators, operators for chaining tasks, DSLs for constraint
> systems, etc” (me, from last time).
>
> More from last time:
>
> - for class types, regardless of whether one is a base of the other or
> both share a common third base type, neither static nor instance methods
> completely solve the problem and won't until/unless Swift supports multiple
> dispatch, and the proposed behavior is not a regression in those cases
>
> I guess I’m not convinced of the chain of reasoning here. “Multi-method
> dispatch is the most correct way to solve the problem” is fine; “therefore,
> anything short of that isn’t worth doing” is where I get stuck. Instance
> methods partially solve the problem, and it’s possible (again, no data on
> hand) that they solve the problem in the majority of cases.
>
> (It’s also possible that the prevalence of OO has made people prefer
> operators that can be dispatched based on the left-hand side, so I guess
> I’d want to go look at, e.g. Haskell and Perl to see what operators don’t
> fit in that bucket.)
>
>
> I guess I’d summarize my stance as “this proposal enshrines our current
> problems with operator semantics in order to improve consistency in the
> syntax” (with “enshrines” meaning “makes harder to change later”), and that
> doesn’t seem like a good enough reason to change from what we have now.
>
>
> …and I have to say I still feel that way. It’s not clear how much of a
> performance win we’ll get, and it’s not clear these are the right
> semantics, and it *is* clear that operators interact poorly with classes.
>
>
> This is a good point, and one that’d I’d missed from the previous
> discussions. Left-bias is probably defensible
>

Jumping in where I don't really have any business: left-bias for all infix
operators, or left-bias for left-associative operators and right-bias for
right-associative operators?


> , but I’m happy to do the conservative thing here: require the operator to
> be ‘final’. That’s no worse than what we have today—you have to delegate to
> something that’s explicitly dynamically dispatched based on whichever of
> the types you choose—and leaves open the possibility of loosening the rule
> in the future.
>
> Jordan
>
> P.S. The proposal also has this line:
>
> non-static operator method syntax be *deprecated* in Swift 2 and *removed* in
> Swift 3
>
>
> which should be updated in one way or another.
>
>
> Sure.
>
> - Doug
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160713/2d2d7a82/attachment.html>


More information about the swift-evolution mailing list