> On May 5, 2017, at 1:33 PM, Tony Allevato <[email protected]> wrote: > > > > On Fri, May 5, 2017 at 11:07 AM Matthew Johnson <[email protected] > <mailto:[email protected]>> wrote: >> On May 5, 2017, at 10:45 AM, Tony Allevato via swift-evolution >> <[email protected] <mailto:[email protected]>> wrote: >> >> Thanks for your feedback, everybody! > > Thanks for continuing to drive this forward! > >> >> I've updated the gist >> <https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad> to >> reflect what seems to be a consensus here: >> >> * Derived conformances are now opt-in (this makes the recursive case *much* >> cleaner, and the complexity involved in that section has been completely >> removed) > > Can the opt-in conformance be declared in an extension? If so, can the > extension be in a different module than the original declaration? If so, do > you intend any restrictions, such as requiring all members of the type > declared in a different module to be public? My initial thought is that this > should be possible as long as all members are visible. > > Declaring the conformance in an extension in the same module should > definitely be allowed; I believe this would currently be the only way to > support conditional conformances (such as the `Optional: Hashable where > Wrapped: Hashable` example in the updated draft), without requiring deeper > syntactic changes. > > I'm less sure about conformances being added in other modules, but I'm > inclined to agree with your assessment. I could see two ways of interpreting > it: > > * E/H can only be derived in an extension in an external module if all the > members are accessible (and the other conditions are met). > * E/H can be derived in an extension in an external module using only the > subset of accessible members (if the other conditions are met). > > These are subtly different. The argument for the first would be "if you want > to add E/H to a type in a different module, you must *consciously* decide > which members you want to use in those computations". The argument for the > second would be "you can already make a type in a different module conform to > E/H and you'd be restricted to the accessible members there, so let's make > that path easier for users too." > > The first case is probably the safer choice. I'm not sure about the > implementation difficulty of each. > > >> * Classes are supported now as well >> >> Please take a look at the updated version and let me know if there are any >> concerns! If folks like it, I'll prepare a pull request. > > Will the synthesis for classes dispatch through a non-final method which is > expected to be overridden by subclasses? You don’t explicitly state this but > it seems implied. If so, what if the subclass requires a custom > implementation? This would require the signature of the non-final method to > be part of the synthesis contract. > > Supporting non-final classes introduces enough complexity (especially when > multiple modules are involved). I would hate to see it get sidetracked in > discussions regarding non-final classes and miss the Swift 4 window because > of that. Given the limited time left for Swift 4 it might be better to keep > the initial proposal simpler and consider a followup in the Swift 5 timeframe > to build on the initial proposal. > > For ==, the operator must already be "class final" or "static" regardless of > this proposal, and it can't be "overridden" as such in subclasses because the > arguments would be different (lhs and rhs would be the subclass, not the > superclass). So the compiler should be able to generate the correct > implementation for subclasses in all cases, right?
This won’t work because Equatable has a `Self` requirement so the `==` defined by the initial conforming class would be called. In order to support non-final classes you would need to have that dispatch through something like an `isEqual` method which *can* be overridden. > > For hashValue, I think the possibilities are: > > * Sub is a subclass of Super. Super conforms to Hashable and implements > non-final hashValue. The compiler can derive it for Sub and call > super.hashValue in its implementation. Yes, this makes sense. The primary difficulty with Hashable is that it refines Equatable. Refining a non-final implementation of `hashValue` is relatively straightforward. > * Sub is a subclass of Super. Super conforms to Hashable and implements a > final hashValue. The compiler cannot derive one for Super and would silently > not do so. Do you mean “the compiler cannot derive one for Sub”? > * Sub is a subclass of Super. Super does not conform to Hashable, but Sub > asks to derive it. This can either (1) not be allowed, telling the user that > they need to write it manually in this case, or (2) be allowed and use all > accessible members to compute the hashValue (including those from the > superclass). > > What do Encodable/Decodable do in these situations? It seems similar > solutions there would apply here. That’s a good question. I don’t recall whether this was addressed explicitly or not. > > But after writing this all out, I'm inclined to agree that I'd rather see > structs/enums make it into Swift 4 even if it meant pushing classes to Swift > 4+x. That is reasonable. On the other hand, I think you could come up with straightforward semantics for synthesizing conformance for final classes as well. Final classes with no superclass should be straightforward. Final classes that do have a superclass would be similarly straightforward if we decide to allow this as described in option (2) above regarding hashValue. I’m on the fence on this - if we can include final classes using option (2) without jeopardizing getting this in for Swift 4 I would support that. If it’s going to put support for value types in Swift 4 at risk then I would not. > > > >> >> >> On Fri, May 5, 2017 at 8:16 AM Nevin Brackett-Rozinsky via swift-evolution >> <[email protected] <mailto:[email protected]>> wrote: >> On Fri, May 5, 2017 at 1:47 AM, Xiaodi Wu via swift-evolution >> <[email protected] <mailto:[email protected]>> wrote: >> On Fri, May 5, 2017 at 12:41 AM, Brent Royal-Gordon <[email protected] >> <mailto:[email protected]>> wrote: >> I would think only final classes could participate in this, since a >> subclassable class would need to allow subclasses to override equality, and >> you can't override a static `==` operator method. >> >> I work so rarely with classes that I'm embarrassed to have to ask this >> question: can classes not satisfy Equatable with a `public class func ==`? >> >> Currently: >> >> class C: Equatable { >> class func == (lhs: C, rhs: C) -> Bool { >> return lhs === rhs >> } >> } >> >> Yields an error, “Operator '==' declared in non-final class 'C' must be >> 'final'”. >> >> Nevin >> _______________________________________________ >> swift-evolution mailing list >> [email protected] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
