newtype feels like a leaky abstraction. Since the new type carries all the protocol conformance and members of the original type, in your example, I could add or divide RecordIds; but if they're database concepts, why would I want to do that?
If the original type were extended to add members or protocols, would the newtype gain those as well? It must, since types can be split into extensions like that in Swift a priori. So the new type is always effectively a subtype of the original, when what you often want is something that starts off with a smaller subset of its operations instead, and people can extend it in ways you don't expect. I'm trying to imagine types where I automatically want *every* operation of its originating type, and having trouble. Even for a unit-like API, there are likely to be arithmetic operations that don't make sense. I think a better model would be a general protocol forwarding mechanism for existing type constructs. Then I could define RecordId as a struct, internally it might have an underlying Int representation, but I would explicitly state which protocols I wanted the type to conform to and which of those are forwarded to that underlying Int. This allows us to maintain the semantic importance of protocols and build types in a way that fits existing Swift patterns, and without the magic/danger that newtype could provide. The drawback is that if you want only a subset of operations in a protocol, you don't get that easily for free. But you could define your own protocol, retroactively conform the origin type to it *internally*, and then publicly conform the new type and forward... and as far as I can tell, that plugs the abstraction's leaks. On Thu, Mar 2, 2017 at 4:08 PM Anton Zhilin via swift-evolution < [email protected]> wrote: > 2017-03-03 2:13 GMT+03:00 Slava Pestov <[email protected]>: > > Does newtype add any new capability that’s not already covered by defining > a struct? > > newtype would forward all members and conformances of the underlying type: > > newtype RecordId = Int > let x: RecordId = 5let y = x + 10 > extension RecordId { > func load() -> String { … } > } > let a = x.load()let b = 42.load() // error > > newtypes aim to carry purely semantic information, in this case, that > those integers can be used to fetch records from a database. We get > additional members only when we are sure that semantic of current instance > is appropriate. > > As a side effect, it essentially allows to declare one-liner structs with > pattern matching. But I agree with Jaden, just adding pattern matching to > structs feels more practical. And this feature is more or less orthogonal > to the core functionality of newtype. > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
