[swift-evolution] [Proposal] Explicit Synthetic Behaviour

Haravikk swift-evolution at haravikk.me
Tue Sep 5 15:02:16 CDT 2017

Some of you will have seen my impassioned pleas on the synthesised Equatable/Hashable thread against implementing implicit synthesised behaviour on protocols that must, by necessity, make assumptions about a concrete type that could be incorrect.

For those that haven't, the concept of synthetic behaviour in discussion here is essentially any kind of default behaviour for a protocol that is automatically generated based upon the concrete type itself (rather than just what the protocol defines). Currently this refers to compiler magic as proposed for Codable, Equatable and Hashable, but also includes the reflection API and any future native macro support for Swift. Using any of these to implement default methods for protocols should IMO be made explicit to developers using any such protocol so that they can specifically opt-in to the behaviour only if they want to and understand what it does.

This proposal idea is essentially for a new attribute @synthetic (name is up for debate). This attribute is required for any default implementation that includes reflective type compiler magic, use of the reflection API against `self` or, in future, any native Swift macros within the method (possibly limited to specific features, will depend on the macro language and its capabilities). If a default method does not have this attribute, then the compiler will produce an error with the appropriate fix-it. For convenience this attribute can be applied to any extension block or even a protocol definition in order to mark all methods in that block/type as synthetic, though it's worth noting that doing so will prevent these default implementations from being provided if they don't actually need this attribute.

Basically the intention is that any protocol default implementation that requires more knowledge about the concrete type than merely what the protocol (and its parents) provide direct access to, must be marked as synthetic.

To use the synthetic behaviour of a protocol, developers must then use the @synthetic keyword when conforming to it, explicitly indicating that they want the extra behaviours rather than implementing the method(s) for themselves. To ignore the synthetic behaviour (and thus require some kind of manual implementation of methods as normal), simply omit the keyword:

	struct Foo : @synthetic Equatable { var someData:String }
		// Type fully conforms to Equatable using synthetic behaviour (equatable properties must be equal)
	struct Foo : Equatable { var someData:String }
		// Error due to unimplemented methods, but offers @synthetic as a fix-it if all unimplemented methods are @synthetic

It is possible that the attribute could be expanded to have parameters, allowing for synthetic conformance only on specific methods, but I'm unsure if that'd be the best way to do it, or how likely that is to be needed.

With this kind of explicit declaration it becomes obvious within code when a developer is specifically choosing to benefit from synthetic behaviour; this hopefully makes it more likely that a developer will fully consider what the implications of this may be, rather than doing it accidentally. The idea in part is to distinguish such types as having separate protocol and synthesised behaviour, where conformance without the @synthetic attribute specifically requires that all protocol requirements be met in full, and that any default behaviour is implemented only on the basis of the protocol itself, while adding @synthetic identifies that more invasive automated behaviour is permitted/requested.

At this stage I don't think there should be much of an impact for existing code; as far as I can tell it should only affect any protocols that happen to be using Mirror(reflecting: self) for some reason within a default implementation, which I can't imagine represents a huge subsection of existing code, and the fix is the simple addition of an attribute.

Anyway, this is basically just a rough dump of the ideas for how the synthesised Codable, Equatable and Hashable behaviours (and anything else anyone can think of) should be changed before Swift 4 is released. I'm hoping for feedback before I make a formal proposal as I don't have a lot of time at the moment, so am looking to do the more structured document once stuff has been hammered out a bit.

- Haravikk
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170905/915814ba/attachment.html>

More information about the swift-evolution mailing list