> On Jul 12, 2017, at 3:23 AM, Gor Gyolchanyan via swift-evolution 
> <[email protected]> wrote:
> 
> Hello, swift community!
> 
> Recently I’ve come across a dilemma regarding value-type semantics when 
> dealing with generic types.
> Consider a protocol that has a mutating in-place function and a non-mutating 
> returning variant of that function:
> 
> protocol Transmogrifier {
> 
>     mutating func transmogrify()
> 
>     func transmogrified() -> Self
> 
> }
> 
> One of these methods has to have a default implementation in terms of the 
> other.
> 
> One way doing it is to implement the mutating version in terms of 
> non-mutating because it doesn’t depend on additional conditions to work, 
> since assigning to `self` causes a complete copy of the internal state of the 
> object regardless of whether it’s a value type or a reference type. However, 
> this approach has a big downside: in many cases mutating functions mutate 
> only part of the instance, which means that an efficient implementation will 
> have to implement the mutating version and because of the way the default 
> implementation works, the non-mutating version would also need to be manually 
> implemented, which makes the default implementation useless in those cases.
> 
> Implementing the non-mutating version in terms of mutating version solves 
> this problem nicely, allowing one to focus on mutating only the necessary 
> parts of the instance, while leaving the need to return a separate instance 
> to the default implementation, which would be perfectly adequate in most 
> cases. This approach has its own problem that this pitch seeks to solve. The 
> problem becomes apparent when you consider this naive implementation:
> 
> extension Transmogrifier {
> 
>     public func transmogrified() -> Self {
>         var result = self
>       result.transmogrify()
>       return result
>     }
> 
> }
> 
> The above implementation is only correct for value types, because assignment 
> is a deep copy. If the instance is of a reference type, the assignment will 
> do nothing and the call to the mutating version will apply to the original 
> object, violating the postcondition of the function (which states that the 
> function shall not modify the instance in any way).
> 
> The most straight-forward way of solving this problem is to introduce a new 
> protocol for making sure the original instance is always copied:

Immutable types like NSString, NSDictionary etc just return self for the copy.

> 
> protocol CopyInitializable {
> 
>     init(copying other: Self)
> 
> }
> 
> In which case the default implementation becomes fully correct:
> 
> // The `CopyInitializable` conformance can also be moved to the protocol 
> itself
> // if the protocol conformance requires value-type semantics.
> extension Transmogrifier where Self: CopyInitializable {
>     
>     public func transmogrified() -> Self {
>         var result = Self(copying: self)
>       result.transmogrify()
>       return result
>     }
> 
> }
> 
> The downside of this approach is the need to manage CopyInitializable 
> conformance of the types  that becomes extra hassle that seems to conflict 
> with the behavior of value types.
> 
> This pitch proposes adding CopyInitializable protocol to the swift standard 
> library and having the compiler automatically generate conformance to it for 
> all value types.
> This would immediately solve all problems of correct convenient 
> implementations of non-mutaiting variants of in-place functions as well as 
> remove the hassle of having to manage conformance to CopyInitializable for 
> all value types that are guaranteed to have this behavior in the first place.
> 
> An good use case would be the NSNumber class, which would conform to 
> CopyInitializable and make use of a single obvious mutating-to-nonmutating 
> implementation of arithmetic operations that would work equally well on all 
> standard numeric types.


NSNumber is an immutable reference type, so copy just returns a strong 
reference to itself. So how would a copy initialization of a NSNumber add any 
value? If we were to add a copy initializer to NSNumber, it would probably be 
implemented as just replacing self in the init with the other object.

For reference types there is already a protocol for what you are attempting to 
do; NSCopying (granted it probably should have a Self return instead of Any… 
but that is a different can-o-worms).

> 
> I’d like to hear opinions regarding this pitch and in case of consensus, I’d 
> write an official proposal and offer it for review.
> 
> Regards,
> Gor Gyolchanyan.
> 
> _______________________________________________
> 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

Reply via email to